- Um comando simples para resolver o antigo problema de limpar branches Git foi encontrado em documentação interna de desenvolvimento da CIA
git branch --merged | grep -v "\*\|master" | xargs -n 1 git branch -d
- O comando remove em lote os branches mesclados, exceto o branch atual e o master, a partir do resultado de
git branch --merged
- Também existe uma versão modificada para projetos modernos, excluindo os branches
main e develop
- Dá para registrá-lo como alias do Git para automatizar tarefas repetitivas e, embora seja simples, é uma ferramenta útil para melhorar continuamente a eficiência do trabalho e manter o repositório organizado
Dica de Git encontrada no Vault7
- Os documentos Vault7, divulgados pelo WikiLeaks em 2017, incluíam ferramentas de hacking da CIA e documentos internos de desenvolvimento
- Entre eles havia uma página com uma coletânea de dicas e truques de Git, e a maior parte tratava de usos comuns como corrigir commits, usar stash e bisect
- Um comando de uma linha encontrado nesse material continua no meu
~/.zshrc até hoje
O problema dos branches antigos
- Em repositórios Git locais, com o tempo, branches já mesclados vão se acumulando, o que dificulta a organização
- Branches de feature, hotfixes e experimentos continuam aparecendo mesmo depois do merge, deixando a lista de
git branch confusa
- O comando
git branch --merged permite ver os branches já mesclados, mas apagá-los manualmente é trabalhoso
O comando original do documento da CIA
Versão modernizada do comando
- Como a maioria dos projetos usa o branch
main, o comando pode ser adaptado assim
git branch --merged origin/main | grep -vE "^\s*(\*|main|develop)" | xargs -n 1 git branch -d
- Ao executá-lo no branch
main após o deploy, dezenas de branches podem ser reduzidos a apenas alguns
- Também é possível registrar esse comando como alias para executá-lo com praticidade
alias ciaclean='git branch --merged origin/main | grep -vE "^\s*(\*|main|develop)" | xargs -n 1 git branch -d'
- Depois disso, basta digitar
ciaclean no repositório para fazer a limpeza automaticamente
Eficiência e praticidade
- Esse comando ajuda a economizar alguns minutos por semana e a manter a lista de branches limpa
- Embora simples, é visto como uma ferramenta prática que proporciona ganhos contínuos de produtividade
4 comentários
Tem alguém nos comentários do HN dizendo que usa um programa que eu criei.
Eu também uso um alias chamado
git gone. É muito prático - alias.gone = ! git fetch -p && git for-each-ref --format '%(refname:short) %(upstream:track)' | awk '$2 == "[gone]" {print $1}' | xargs -r git branch -DEu não uso git puro, mas estou organizando com uma ferramenta chamada gh-poi.
https://github.com/seachicken/gh-poi
Comentários do Hacker News
Eu uso um alias chamado
git tidypara limpar branchesNão apaga as branches padrão (
main,master) e também não mexe na branch atual nem em branches de outros worktreesBranches que sumiram do remoto também são apagadas automaticamente, e o código está na configuração dos meus dotfiles
init.defaultBranché arriscado. O nome da branch padrão pode variar por repositório, e essa configuração é global, então precisa ser definida de antemãoEu criei um alias chamado
git defaultpara detectar automaticamente a branch padrão real no remoto (origin)Eu uso um comando de limpeza integrado ao
fzfDá para pré-selecionar branches mescladas e apagá-las de uma vez, e também excluir algumas se quiser
Ele também limpa as branches remotas, e o código está na minha configuração do .gitconfig
Além disso, uso a variável
user.primaryBranchpara definir branches padrão diferentes por repositórioinit.defaultBranchno lugar também funcione. Mesmo em repositórios já inicializados, dá para configurar comgit config --local init.defaultBranch maingit pull origin main:maine depoisgit rebase maingit branch --mergednão funciona direito em repositórios que usam squash mergeIsso porque o SHA do commit resultante do squash é diferente do HEAD original da branch
Tenho curiosidade sobre ferramentas que consigam detectar com segurança branches que passaram por squash
Não é perfeito, mas é bem prático, e sempre mostra um prompt de confirmação antes de apagar
Consultei a configuração de exclusão automática de branches do GitHub
Na maioria dos casos, isso é tratado com um hook no evento de exclusão da branch remota
Uso um alias chamado
git gonepara rodargit fetch -pe depois limpar branches no estado[gone]Por isso uso um script que combina três métodos:
git branch --merged,git cherryegit log grepAinda assim, podem ocorrer falsos positivos se commits tiverem sido amendados ou se houver vários commits
Eu uso um alias chamado
git lintpara limpar branches mescladasEle exclui
main,masterestable, e eu costumo usar bastante a combinaçãogit pull --prune && git lintO comando Git em si é comum, mas foi interessante acabar vendo um documento cuja fonte era o Wikileaks ao clicar
O projeto “Fine Dining” da CIA era uma ferramenta para disfarçar malware escondido em USB como se fosse um aplicativo
O problema original também poderia ser resolvido simplesmente imprimindo a lista de branches não mescladas
É estranho que uma tarefa tão natural exija várias linhas de bash
Com uma base de código tão grande, é uma pena que o Git não ofereça isso como recurso nativo
Consultei também este post de blog relacionado
xargsou de loopfor, isso vira algo trivialTransformar isso em comando embutido pode até acabar sendo mais complexo, porque teria de lidar com muitos casos de exceção
No fim, também houve a reação de que “parece alguém que acabou de aprender xargs”
Eu mesmo aprendi coisas assim por blogs e textos no passado
xargs, isso por si só já é legalUltimamente estou viciado em TUI. Quando algo é desconfortável de usar, peço ao Claude-code para criar uma TUI para mim
Usei a biblioteca Textual para criar uma TUI de gerenciamento de Git worktree, e o Claude lida muito bem com código Python
tig, uma TUI antiga para Git. É boa até para buscar inspiraçãoVale consultar também este texto sobre a funcionalidade de rebase do Magit
Eu também implementei algo parecido no Fish shell
É uma função para selecionar com
fzfbranches que sumiram do remoto e apagá-lasEstá no código dos meus dotfiles