Rimuovere i rami di tracciamento non più sul telecomando


1173

Esiste un modo semplice per eliminare tutti i rami di monitoraggio il cui equivalente remoto non esiste più?

Esempio:

Filiali (locali e remote)

  • maestro
  • origin / master
  • origine / bug-fix-a
  • origine / bug-fix-b
  • origine / bug-fix-c

A livello locale, ho solo un ramo principale. Ora ho bisogno di lavorare su bug-fix-a , quindi lo controllo, ci lavoro e invio le modifiche al telecomando. Quindi faccio lo stesso con bug-fix-b .

Filiali (locali e remote)

  • maestro
  • bug-fix-a
  • bug-fix-b
  • origin / master
  • origine / bug-fix-a
  • origine / bug-fix-b
  • origine / bug-fix-c

Ora ho master filiali locali , bug-fix-a , bug-fix-b . Il manutentore del ramo Master unirà le mie modifiche al master ed eliminerà tutti i rami che ha già unito.

Quindi lo stato attuale è ora:

Filiali (locali e remote)

  • maestro
  • bug-fix-a
  • bug-fix-b
  • origin / master
  • origine / bug-fix-c

Ora vorrei chiamare alcuni comandi per eliminare i rami (in questo caso bug-fix-a , bug-fix-b ), che non sono più rappresentati nel repository remoto.

Sarebbe qualcosa come il comando esistente git remote prune origin, ma più simile git local prune origin.

Risposte:


1282

git remote prune origin elimina i rami di rilevamento non sul telecomando.

git branch --merged elenca i rami che sono stati uniti nel ramo corrente.

xargs git branch -d elimina i rami elencati sull'input standard.

Fare attenzione a eliminare i rami elencati per git branch --merged. L'elenco potrebbe includere mastero altri rami che preferisci non eliminare.

Per darti l'opportunità di modificare l'elenco prima di eliminare i rami, puoi eseguire le seguenti operazioni in una riga:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

17
La prima riga dei rami uniti è * mastersul mio sistema. Il seguente comando ha funzionato per me:git branch -d $(git branch --merged |tail -n +2)
Trendfischer,

99
Se sono acceso developallora git branch --mergedinclude master! Probabilmente (sicuramente!) Non vuoi eliminarlo. Penso anche che dovrebbe essere git branch -ddove le lettere minuscole -dsignificano "eliminazione sicura", ad esempio eliminano solo se unite.
Thom_nic,

11
Sembra una soluzione migliore è fornita .
Sergey Brunov,

34
Rimosso unito è utile, ma non è lo stesso di "rimuovi rami non in remoto".
dlsso,

11
Basta usare grep per escludere master:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
geniass

592

Dopo il comando

git fetch -p

rimuove i riferimenti remoti, quando si esegue

git branch -vv

mostrerà 'andato' come stato remoto. Per esempio,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

Quindi puoi scrivere un semplice script per rimuovere i rami locali che sono passati ai telecomandi:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

Si noti che quanto sopra utilizza il comando "porcelain" git branchper ottenere lo stato a monte.

Un altro modo per ottenere questo stato è usare il comando "idraulico" git for-each-refcon la variabile di interpolazione %(upstream:track), che sarà [gone]proprio come sopra.

Questo approccio è in qualche modo più sicuro, poiché non vi è alcun rischio di corrispondenze accidentali su parte del messaggio di commit.

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

8
@KrzysztofWende - non su Solaris e alcuni BSD e alcuni OS X :)
jww

4
Sembra che questo rimuoverà anche qualsiasi ramo "andato" nell'ultimo messaggio di commit.
dlsso,

11
@dlsso Se l'ultimo messaggio di commit contiene la stringa ": gone]", anche sì verrà rimosso. Puoi renderlo più robusto a spese della semplicità avendo un awk / gawk aggiuntivo per eliminare il messaggio di commit. git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
jason.rickman,

2
In risposta al mio commento precedente (domanda), l'attuale ramo ha * come primo campo. Se capita di trovarsi anche nella lista dei rami "spariti", verranno assegnati $ 1 * e saranno interpretati come filespec con awk che sputa nomi di file e cartelle. Ho eliminato l'espressione grep e awk avevo fare tutto il filtraggio: awk '/: gone]/{if ($1!="*") print $1}'. Questo ora funziona come previsto.
rhaben,

5
@ahmedbhs poiché il comando usa la virgoletta singola "è necessario usare la virgoletta doppia" per circondare l'intero comando. Inoltre, gli alias git che sono comandi di shell (come questo) richiedono all'inizio! Questo funziona per me:test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
jason.rickman

307

La maggior parte di queste risposte in realtà non risponde alla domanda originale. Ho fatto un sacco di scavi e questa è stata la soluzione più pulita che ho trovato. Ecco una versione leggermente più approfondita di quella risposta:

  1. Dai un'occhiata al tuo ramo predefinito. Generalmentegit checkout master
  2. Correre git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Spiegazione:

Funziona eliminando i rami di tracciamento e quindi eliminando quelli locali che mostrano che sono "andati" dentro git branch -vv.

Appunti:

Se la tua lingua è impostata su qualcosa di diverso dall'inglese, dovrai cambiare gonela parola appropriata. Le filiali che sono solo locali non verranno toccate. I rami che sono stati eliminati in remoto ma che non sono stati uniti mostreranno una notifica ma non verranno eliminati in locale. Se vuoi eliminare anche quelli, cambia -din -D.


2
per il sistema operativo francese sparito devono essere cambiati per disprezzo
Mohamed EL HABIB il

4
dovrebbe aggiungere LANG = en_US prima di git branch per forzare l'inglese: git fetch --prune && LANG = en_US git branch -vv | awk '/: gone] / {print $ 1}' | xargs git branch -d
Mohamed EL HABIB il

3
Aggiungerei git checkout master && ...all'inizio del comando.
iarroyo,

2
Questo è pericoloso quando sei su un ramo che dovrebbe essere eliminato - in quel caso la prima colonna è '*', che viene quindi passata a xargs. Per migliorarlo, aggiungi il carattere '*' prima di passare l'output a awk: sed -e 's / ^ * //'
meeee,

6
! attento Esiste un caso limite che comporterà l'eliminazione di tutti i rami locali: se si è attualmente in un ramo che è stato eliminato in remoto, l'output di git branch -vvinizierà con un asterisco che alla fine si tradurrà in esecuzione git branch -d *. Ecco una versione patchata che ignorerà le linee con l'asterisco:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
kcm

210

Normalmente non risponderei a una domanda che ha già 16 risposte, ma tutte le altre risposte sono sbagliate e la risposta giusta è così semplice. La domanda dice "Esiste un modo semplice per eliminare tutti i rami di monitoraggio il cui equivalente remoto non esiste più?"

Se "semplice" significa cancellarli tutti in una volta, non fragili, non pericolosi e senza fare affidamento su strumenti che non tutti i lettori avranno, allora la risposta giusta è: no.

Alcune risposte sono semplici, ma non fanno ciò che è stato chiesto. Altri fanno ciò che è stato chiesto, ma non sono semplici: tutti fanno affidamento sull'analisi dell'output di Git tramite comandi di manipolazione del testo o linguaggi di script, che potrebbero non essere presenti su tutti i sistemi. Inoltre, la maggior parte dei suggerimenti utilizza comandi di porcellana, il cui output non è progettato per essere analizzato dallo script ("porcellana" si riferisce ai comandi destinati al funzionamento umano; gli script devono utilizzare i comandi "idraulico" di livello inferiore).

Ulteriori letture:


Se vuoi farlo in modo sicuro, per il caso d'uso nella domanda (rami di tracciamento garbage-collection che sono stati eliminati sul server ma esistono ancora come rami locali) e solo con comandi Git di alto livello, devi

  • git fetch --prune(o git fetch -p, che è un alias o git prune remote originche fa la stessa cosa senza recuperare, e probabilmente non è quello che vuoi la maggior parte del tempo).
  • Nota eventuali rami remoti segnalati come eliminati. Oppure, per trovarli in seguito, git branch -v(qualsiasi ramo di tracciamento orfano verrà contrassegnato come "[scomparso]").
  • git branch -d [branch_name] su ciascun ramo di tracciamento orfano

(che è quello che propongono alcune delle altre risposte).

Se vuoi scrivere una soluzione, allora for-each-refè il tuo punto di partenza, come nella risposta di Mark Longair qui e questa risposta a un'altra domanda , ma non riesco a vedere un modo per sfruttarla senza scrivere un ciclo di script di shell o usare xargs o qualcosa del genere .


Spiegazione di fondo

Per capire cosa sta succedendo, devi apprezzare che, nella situazione del monitoraggio dei rami, non hai un ramo, ma tre. (E ricorda che "branch" significa semplicemente un puntatore a un commit.)

Dato un ramo di tracciamento feature/X, il repository remoto (server) avrà questo ramo e lo chiamerà feature/X. Il repository locale ha un ramo remotes/origin/feature/Xche significa "Questo è ciò che il telecomando mi ha detto che la sua caratteristica / ramo X era, l'ultima volta che abbiamo parlato", e infine, il repository locale ha un ramo feature/Xche punta al tuo ultimo commit ed è configurato per "traccia" remotes/origin/feature/X, nel senso che puoi tirare e spingere per mantenerli allineati.

Ad un certo punto, qualcuno ha eliminato il feature/Xsul telecomando. Da quel momento, rimani con il tuo locale feature/X(che probabilmente non vuoi più, dal momento che il lavoro sulla funzione X è presumibilmente finito), e il tuo remotes/origin/feature/Xche è certamente inutile perché il suo unico scopo era di ricordare lo stato del ramo del server .

E Git ti consentirà di ripulire automaticamente il ridondante remotes/origin/feature/X- questo è ciò che git fetch --prunefa - ma per qualche motivo, non ti consente di eliminare automaticamente i tuoi feature/X... anche se feature/Xcontiene ancora le informazioni di tracciamento orfane, quindi ha le informazioni per identificare ex rami di tracciamento che sono stati completamente uniti. (Dopo tutto, si può dare voi le informazioni che ti permette di fare l'operazione a mano da soli.)


3
Questa è una risposta molto più sicura. Inoltre, funzionerà se si utilizza un flusso di lavoro "Squash and Merge", a differenza della risposta selezionata.
Jake Levitt,

3
Questo in realtà risponde solo alla parte semplice della domanda "come trovare rami andati" (e che con lo stesso comando già pubblicato da jason.rickman nel 2015) ma poi ti dice di eliminare manualmente tutti i rami che è esattamente ciò che l'OP non vuole fare.
Voo,

4
@Voo Questo è il punto della risposta: non dirti come farlo (è solo un bonus) ma dirti che la risposta è che non esiste un modo facile e semplice per farlo. Qual è la risposta corretta alla domanda così come è stata formulata.
Andrew Spencer,

1
"Se vuoi farlo in modo sicuro, per il caso d'uso nella domanda .." - che nega la maggior parte delle affermazioni del primo paragrafo. "[Git] può darti le informazioni che ti consentono di eseguire l'operazione manualmente" - siamo programmatori, quindi date le informazioni come un elenco (che viene mostrato) l'attività è ancora semplice (ad es. xargs). C'è anche git aliasda semplificare una serie di casi.
user2864740

2
@ user2864740 Alcuni lettori potrebbero considerare che scrivere un piccolo script bash rientri nella loro definizione di "semplice", e questa è una posizione perfettamente difendibile, ma ho dato la mia interpretazione di "semplice" nel secondo paragrafo e il resto della risposta è coerente con esso. E a difesa della mia interpretazione dichiaratamente restrittiva, non tutti gli utenti di Git hanno xargso bash, e probabilmente non sono qui alla ricerca di una sfida di microcodifica, tanto quanto una risposta rapida possono applicare in modo sicuro senza distrarsi ulteriormente dal loro vero obiettivo .
Andrew Spencer,

52

Ho trovato la risposta qui: come posso eliminare tutti i rami git che sono stati uniti?

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

Assicurati di essere padrone

Puoi assicurarti che master, o qualsiasi altro ramo per quella materia, non venga rimosso aggiungendo un altro grepdopo il primo. In tal caso andresti:

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

Quindi se volessimo mantenere master, develope stagingper esempio, andremmo:

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

Rendi questo un alias

Dal momento che è un po 'lungo, potresti voler aggiungere un alias al tuo .zshrco .bashrc. Il mio si chiama gbpurge(per git branches purge):

alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'

Quindi ricaricare il tuo .bashrco .zshrc:

. ~/.bashrc

o

. ~/.zshrc

8
Utile, ma non uguale a "rimuovi rami non in remoto"
dlsso

Greate risposta @karlingen, ho questo in modo permanente come gbpurge in tutti i miei ambienti di sviluppo
Peter Dolan

50

Soluzione Windows

Per Microsoft Windows Powershell:

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

spiegazione

git checkout master passa al ramo principale

git remote update origin --prune pota i rami remoti

git branch -vvottiene un output dettagliato di tutti i rami ( riferimento git )

Select-String -Pattern ": gone]" ottiene solo i record in cui sono stati rimossi dal remoto.

% { $_.toString().Trim().Split(" ")[0]} ottenere il nome del ramo

% {git branch -d $_} cancella il ramo


3
Grazie per questo, anche se ho dovuto aggiungere un .Trim()dopo .toString()per rimuovere due spazi prima del nome del ramo.
Matteo,

2
Grazie per questo comando Ho dovuto cambiare il git branch -din git branch -Daltrimenti ottengo l'errore il ramo non è completamente unito.
markieo,

1
@markieo Probabilmente lo sai già, ma per chiunque altro - git branch -Dè distruttivo e cancellerà il lavoro locale che non hai ancora spinto. -dè sempre sicuro, stai solo attento -D.
Nate Barbettini,

33

Il pattern matching per "sparito" nella maggior parte delle altre soluzioni è stato un po 'spaventoso per me. Per essere più sicuro, questo utilizza il --formatflag per estrarre lo stato di tracciamento a monte di ciascun ramo .

Avevo bisogno di una versione compatibile con Windows, quindi questo elimina tutti i rami elencati come "spariti" usando Powershell:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

La prima riga elenca il nome delle filiali locali il cui ramo a monte è "scomparso". La riga successiva rimuove le righe vuote (che vengono emesse per i rami che non sono "spariti"), quindi il nome del ramo viene passato al comando per eliminare il ramo.


6
L' --formatopzione sembra essere abbastanza nuova; Ho dovuto aggiornare git da 2.10. Qualcosa a 2.16.3 per ottenerlo. Questa è la mia modifica per i sistemi Linux:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D
bxm,

2
Questa è la soluzione migliore finora. Un suggerimento è di usare refname:short. Quindi è possibile eliminare la riga% { $_ -replace '^refs/heads/', '' }
ioudas

2
Questa è un'ottima soluzione per Windows. Lo sto usando in questo modo perché è più leggibile. git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }Probabilmente è una buona idea usare -dinvece di -D. L'eliminazione forzata non dovrebbe essere necessaria per i rami che non sono più sul telecomando.
Rubanov,

31

Rimuovi tutti i rami che sono stati uniti nel master, ma non provare a rimuovere il master stesso:

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

o aggiungi un alias:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

Spiegazione:

git checkout master checkout master branch

git pull origin master assicurarsi che la succursale locale abbia unito tutte le modifiche remote

git fetch -p rimuovere i riferimenti ai rami remoti che sono stati eliminati

git branch -d $(git branch master --merged | grep master -v) elimina tutti i rami che sono stati uniti nel master, ma non provare a rimuovere il master stesso


3
Una nota, questo è molto utile ma rimuoverà anche quei rami che non sono mai stati inviati al telecomando. È più sicuro elencare solo le differenze e poi copiare ciò che vuoi veramente cancellare nel git branch -Dcomando
Zefiryn,

Giusto per chiarire, Zefiryn si riferisce all'utilizzo dell'opzione -D che non fa parte del one-liner.
CS01,

1
O juse il minuscolo git branch -dche dovrebbe emettere un avviso sui rami non spinti.
acme

16
git fetch -p

Questo eliminerà tutti i rami che non esistono più sul telecomando.


64
ciò rimuove i riferimenti remoti, ma non le filiali locali stesse. Pur essendo un comando utile, non credo che questo risponda alla domanda di OP.
Thataustin,

Che cosa? Questo elimina le filiali locali per me.
Alex Hall,

1
@AlexHall Il repository remoto ha un ramo X; tu git checkout X; ora il tuo repository ha un ramo di tracciamento (locale) Xe un ramo remoto origin/X; il repository remoto elimina X; tu git fetch-p; nel tuo repository locale, non solo origin/Xma anche Xsono stati eliminati. È quello che stai dicendo?
Andrew Spencer,

16

Ancora un'altra risposta per il mucchio, attingendo pesantemente dalla risposta di Patrick (che mi piace perché sembra eliminare qualsiasi ambiguità su dove gone]corrisponderà git branchnell'output) ma aggiungendo un * nix piegato.

Nella sua forma più semplice:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

L'ho racchiuso in uno git-gonescript sul mio percorso:

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB: l' --formatopzione sembra essere abbastanza nuova; Ho dovuto aggiornare git da 2.10. Qualcosa a 2.16.3 per ottenerlo.

EDIT: ottimizzato per includere suggerimento circa refname:shortda Benjamin W.

NB2 - Ho provato solo bash, quindi l'hashbang, ma probabilmente portatile sh.


Non puoi saltare la sedparte utilizzando %(refname:short)nella prima riga?
Benjamin W.

Sembra funzionare per me, e ora ce l'ho come un alias Git pulito - la soluzione più pulita di tutti qui!
Benjamin W.

2.13 introdotto --format. Un altro modo per saltare la sedparte è usare git update-ref -d. Si noti che questo è probabilmente un po 'pericoloso, l'utilizzo git for-each-refè più sicuro qui (dato --shell).
gsnedders

Ottima risposta, e mi ha aiutato a rispondere alle mie domande quando mi diletto --formata farlo da solo. Solo una domanda: perché il #!bash? Tutto qui mi sembra portatile sh.
Toby Speight,

Questa è solo la mia normale piastra di cottura e non era stata testata altrove.
bxm

15

Potrebbe essere utile per alcuni, una sola riga per cancellare tutte le filiali locali tranne master e sviluppare

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

Risposta fantastica! Mi piace come si può facilmente giocare con il 'git branch | grep -v "master" | grep -v "develop"tipo di cose prima di impegnarsi ad aggiungere la parte di cancellazione del comando. 👏😊
finneycanhelp

Ma questo non risponde alla domanda sopra. Questo eliminerà i rami anche se il telecomando è ancora lì.
Jim.B,

13

Ciò eliminerà tutte le ramificazioni locali unite tranne il riferimento master locale e quello attualmente in uso:

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

E questo eliminerà tutti i rami che sono già stati rimossi dal repository remoto a cui fa riferimento " origine ", ma sono ancora disponibili localmente in " telecomandi / origine ".

git remote prune origin

git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d Spiegazione: Preferisco sostituire il git branch --mergedcon git branch -vvper mostrare lo stato (sparito) perché il precedente git branch --mergedpuò mostrare anche il master
jpmottin

13

Non penso che ci sia un comando integrato per farlo, ma è sicuro fare quanto segue:

git checkout master
git branch -d bug-fix-a

Quando lo usi -d, git rifiuta di eliminare il ramo a meno che non sia completamente unito HEADo al suo ramo di monitoraggio remoto a monte. Pertanto, è sempre possibile git for-each-refeseguire il ciclo sull'output di e provare a eliminare ogni ramo. Il problema con questo approccio è che sospetto che probabilmente non vuoi bug-fix-dessere cancellato solo perché origin/bug-fix-dcontiene la sua cronologia. Invece, potresti creare uno script simile al seguente:

#!/bin/sh

git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
  if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
  then
    if [ "$r" != "master" ]
    then
      git branch -d "$r"
    fi
  fi
done

Avvertenza: non ho testato questo script: utilizzare solo con cura ...


Mi sono preso la libertà di modificare la sceneggiatura. Ancora non darà alcuna garanzia, ma funziona e sembra funzionare ora.
fwielstra,

13

TL; DR:

Rimuovere TUTTE le filiali locali che non si trovano sul telecomando

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

Rimuovere TUTTI i rami locali che non sono in remoto E che sono completamente uniti E che non sono utilizzati come indicato in molte risposte prima.

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

Spiegazione

  • git fetch -p poterà tutti i rami che non esistono più sul telecomando
  • git branch -vv stamperà i rami locali e i rami potati saranno taggati con gone
  • grep ': gone]' seleziona solo i rami che sono andati
  • awk '{print $1}' filtra l'output per visualizzare solo il nome dei rami
  • xargs git branch -D passerà sopra tutte le linee (rami) e forzerà la rimozione di questo ramo

Perché git branch -De non git branch -daltrimenti avrai per le filiali che non sono completamente unite.

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

1
volevi dire remoto anziché master?
tinos,

8

Potresti farlo:

git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d

7

Sulla base delle informazioni sopra, ha funzionato per me:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

Rimuove tutte le filiali locali con sono ': gone] 'sul telecomando.


1
Sembra che questo rimuoverà anche qualsiasi ramo "andato" nell'ultimo messaggio di commit.
dlsso,

Rimuoverà anche qualsiasi ramo che abbia un gonepunto qualsiasi nel suo nome.
bfontaine,

3
"git branch -D git branch -vv | grep ': gone]' | awk '{print $ 1}' | xargs`" Questo ha funzionato per me.
Muthu Ganapathy Nathan,

7
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

Il comando precedente può essere utilizzato per recuperare i rami che vengono uniti ed eliminati in remoto ed elimina il ramo locale che non è più disponibile in remoto


La migliore soluzione finora, anche se l'ho cambiata grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -Dper forzare l'eliminazione di tutto
Shoaib

Pericoloso se uno dei nomi delle filiali contiene la sottostringa in gonequalsiasi punto (ad es usingonefunction.).
Toby Speight,

7

Niente di tutto questo era davvero giusto per me. Volevo qualcosa che eliminasse tutti i rami locali che stavano monitorando un ramo remoto, su origin, dove il ramo remoto è stato eliminato ( gone). Non volevo eliminare i rami locali che non erano mai stati impostati per tenere traccia di un ramo remoto (es .: i miei rami di sviluppo locali). Inoltre volevo un semplice one-liner che utilizza solo gito altri semplici strumenti della CLI, piuttosto che scrivere script personalizzati. Ho finito per usare un po 'di grepe awkper fare questo semplice comando.

Questo è in definitiva ciò che è finito nel mio ~/.gitconfig:

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

Ecco un git config --global ...comando per aggiungere facilmente questo come 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: nel comando config, utilizzo l' -dopzione git branchpiuttosto che -D, come faccio nella mia configurazione effettiva. Uso -Dperché non voglio sentire Git lamentarsi di rami non uniti. Potresti volere anche questa funzionalità. In tal caso, utilizzare semplicemente -Danziché -dalla fine di quel comando di configurazione.


Mi piace l'approccio alias git. Domanda veloce: perché fare git branch -vve greping per : gone]e non fare git branch -ve grep per [gone]?
Lalibi

@lalibi, bella domanda. Non ricordo. Sospetto che qualcosa non si presentasse con uno solo v. Se git branch -v | grep '[gone]'funziona per te, provaci. Sembra un po 'più pulito.
Karl Wilbur,

4

Basato sul suggerimento Git: eliminazione di vecchi rami locali , che sembra simile alla soluzione jason.rickman Ho implementato un comando personalizzato per questo scopo chiamato git andato usando Bash:

$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
  -p  prune remote branch
  -n  dry run: list the gone branches
  -d  delete the gone branches
  -D  delete the gone branches forcefully

EXAMPLES
git gone -pn    prune and dry run
git gone -d     delete the gone branches

git gone -pn combina la potatura e l'elenco dei rami "spariti":

$ git gone -pn
  bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
  fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules

Quindi puoi premere il grilletto usando git gone -do git gone -D.

Appunti

  • L'espressione regolare che ho usato è "$BRANCH/.*: gone]"dove $BRANCHsarebbe normalmente origin. Questo probabilmente non funzionerà se l'output di Git è localizzato in francese, ecc.
  • Sebastian Wiesner lo ha anche portato su Rust per gli utenti Windows. Quello è anche chiamato git sparito .

Questa dovrebbe probabilmente essere la risposta accettata - git gonesembra un alias per git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d, che risolve il problema del PO.
alex,

4

Attingendo pesantemente da una serie di altre risposte qui, ho finito con il seguente (solo git 2.13 e sopra, credo), che dovrebbe funzionare su qualsiasi shell tipo UNIX:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

Questo utilizza in particolare for-each-refinvece di branch(come branchè un comando "di porcellana" progettato per un output leggibile dall'uomo, non elaborato dalla macchina) e usa il suo --shellargomento per ottenere un output correttamente sfuggito (questo ci consente di non preoccuparci di alcun carattere nel nome ref).


Funziona per me, ma sarebbe anche bello se tu potessi spiegare cosa stanno facendo gli altri passaggi del comando. Ad esempio non so cosa [ ! -z "$ref" ]significhi. Penso che una fodera multipla avrebbe già aiutato. Ma grazie ancora per il tuo contributo!
KevinH,

4

Ancora un'altra risposta, perché nessuna delle soluzioni soddisfa le mie esigenze di eleganza e multipiattaforma:

Comando per eliminare le filiali locali non sul telecomando:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

Per integrarlo con gitconfig in modo che possa essere eseguito con git branch-prune:

bash

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

PowerShell

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(Hai bisogno di aiuto per trovare un comando universale per PowerShell e bash)

Perché questa risposta è la migliore?

  • Offre una soluzione completa: aggiunge un git branch-prunecomando a git
  • Funziona bene da Windows PowerShell
  • L'idea di base è @ jason.rickman 's metodo proiettile usandogit for-each-ref
  • L'analisi e il filtro vengono eseguiti --filtersenza che siano necessarie dipendenze esterne

Spiegazione:

  • Aggiunge un nuovo alias al tuo ~\.gitconfig. Dopo averlo eseguito, puoi semplicemente farlogit branch-prune
  • All'interno di questo alias:
    • Recupera i rami con la --prunebandiera, che "elimina i rami di tracciamento remoto non più sul telecomando"
    • Usi git for-each-refe --filter, per ottenere un elenco dei rami sono [gone](nessun telecomando)
    • Passa attraverso questo elenco ed elimina il ramo in modo sicuro

1
Grazie, @ jerry-wu per aver migliorato la bellezza di questa soluzione all'infinito.
Himura,

@jerry-wu e l'ultima modifica del comando git config non funziona in PowerShell ((
Himura

1

Ho pensato a questo script bash. E tenere sempre i rami develop, qa, master.

git-clear() {
  git pull -a > /dev/null

  local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
  branches=(${branches//;/ })

  if [ -z $branches ]; then
    echo 'No branches to delete...'
    return;
  fi

  echo $branches

  echo 'Do you want to delete these merged branches? (y/n)'
  read yn
  case $yn in
      [^Yy]* ) return;;
  esac

  echo 'Deleting...'

  git remote prune origin
  echo $branches | xargs git branch -d
  git branch -vv
}

1

Uso un metodo breve per fare il trucco, ti consiglio di fare lo stesso in quanto potrebbe risparmiare alcune ore e darti maggiore visibilità

Aggiungi il seguente frammento nel tuo .bashrc (.bashprofile su macos).

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. Prendi tutti i telecomandi
  2. Ottieni solo rami uniti da Git
  3. Rimuovere da questo elenco i rami "protetti / importanti"
  4. Rimuovi il resto (ad es. Rami puliti e uniti)

Dovrai modificare il regex grep per adattarlo alle tue esigenze (qui, impedisce a master, preprod e dmz di essere cancellati)


git fetch --all --pruneha fatto il trucco. Grazie!
LeOn - Han Li,

1

Questo ha funzionato per me:

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

oh, ho postato il doppio su ... ho appena visto questo quando ho esaminato i post. Ma potresti davvero indicare il ragazzo che ha fornito questo comando invece di prenderlo come tuo!
Dwza,

Ho capito da un forum, non cercare di essere intelligente, basta prendere la risposta o ignorarla
Fareed Alnamrouti,

Anche se tu ... comunque ... non sei venuto qui per discuterne con te. Come hai detto ... prendi il mio commento o ignoralo;)
Dwza,

0

Non sono sicuro di quanto tempo, ma ora uso git-up, che se ne occupa.

Lo faccio git upe inizia a tracciare i nuovi rami ed elimina quelli vecchi.

Giusto per chiarire, non è un comando git out-of-box - https://github.com/aanand/git-up

A proposito, stash anche l'albero sporco e fa ancora le modifiche con solo git up.

Spero che sia utile per qualcuno


2
Questo non sta eliminando le filiali locali che non esistono sul server.
Ashley,

0

Ecco una soluzione che uso per il guscio di pesce. Testato su Mac OS X 10.11.5, fish 2.3.0e git 2.8.3.

function git_clean_branches
  set base_branch develop

  # work from our base branch
  git checkout $base_branch

  # remove local tracking branches where the remote branch is gone
  git fetch -p

  # find all local branches that have been merged into the base branch
  # and delete any without a corresponding remote branch
  set local
  for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
    set local $local $f
  end

  set remote
  for f in (git branch -r | xargs basename)
    set remote $remote $f
  end

  for f in $local
    echo $remote | grep --quiet "\s$f\s"
    if [ $status -gt 0 ]
      git branch -d $f
    end
  end
end

Alcune note:

Assicurati di impostare il corretto base_branch. In questo caso uso developcome ramo base, ma potrebbe essere qualsiasi cosa.

Questa parte è molto importante: grep -v "\(master\|$base_branch\|\*\)" . Assicura di non eliminare master o il ramo di base.

Uso git branch -d <branch>come ulteriore precauzione, in modo da non eliminare alcun ramo che non sia stato completamente unito a HEAD upstream o corrente.

Un modo semplice per testare è sostituirlo git branch -d $fcon echo "will delete $f".

Suppongo che dovrei anche aggiungere: UTILIZZARE A PROPRIO RISCHIO!


0

Ho scritto uno script Python usando GitPython per eliminare i rami locali che non esistono sul telecomando.

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)

        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)

        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])


        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

Spero che qualcuno lo trovi utile, per favore aggiungi commenti se ho perso qualcosa.


0

Se si utilizza zshshell con Oh My Zshinstallato, il modo più semplice per farlo in modo sicuro è utilizzare il completamento automatico incorporato.

Innanzitutto determinare con quali rami si desidera eliminare:

~ git branch --merged

  branch1
  branch2
  branch3
* master

questo ti mostrerà un elenco di rami già uniti

Dopo averne conosci alcuni che si desidera eliminare, digitare:

~ git branch -d 

Tutto quello che devi fare è premere [tab] e ti mostrerà un elenco di filiali locali. Usa tab-complete o premi nuovamente [tab] e puoi scorrere attraverso di loro per selezionare un ramo con [invio].

Scheda Selezionare i rami più e più volte fino a quando non si dispone di un elenco di rami che si desidera eliminare:

~ git branch -d branch1 branch2 branch3

Ora premi Invio per eliminare la tua raccolta di rami.

Se non stai usando zsh sul tuo terminale ... Scarica qui.


0

Mi piace usare le pipe perché facilita la lettura del comando.

Questa è la mia soluzione se desideri rimuovere tutti i rami tranne master.

git branch | grep -v master | xargs -n 1 git branch -D

Per eliminare altri rami che corrispondono ai tuoi criteri, modifica il primo e il secondo blocco.

git branch --merged | grep feature_name | xargs -n 1 git branch -D

-3

Ecco la semplice risposta che ha funzionato per me utilizzando un client Git:

Elimina del tutto il repository dal tuo computer, quindi ricontrolla.

Non si scherza con gli script rischiosi.


2
Che dire delle filiali su cui sto attualmente lavorando: /
Mailo Světel,

@ MailoSvětel se sono sul telecomando, puoi semplicemente tirarli di nuovo (ricordati di impegnarti e inviare il tuo ultimo lavoro al telecomando!)
Juan Carlos Ospina Gonzalez,

Nella mia domanda e nella maggior parte delle risposte, stiamo cercando di evitare lavori inutili. In altre parole: quello che devo fare è solo rimuovere i rami, non ci lavorerò più. Rimuovere il repository, clonarlo e ricominciare a rintracciare i rami, è molto lavoro inutile per me. Oltre a ciò, alcuni lavori potrebbero perdersi :(
Mailo Světel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.