Elimina tutti i rami git locali


323

Seguo un processo di sviluppo in cui creo una nuova filiale locale per ogni nuova funzionalità o trama. Al termine, unisco il ramo in master e quindi premo.

Ciò che tende a succedere nel tempo a causa di una combinazione di pigrizia o dimenticanza, è che finisco con un ampio elenco di filiali locali, alcune delle quali (come i picchi) potrebbero non essere state unite.

So come elencare tutti i miei rami locali e so come rimuovere un singolo ramo ma mi chiedevo se esistesse un comando git che mi permettesse di cancellare tutti i miei rami locali?

Di seguito è riportato l'output del git branch --mergedcomando.

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

Tutti i tentativi di eliminare i rami elencati con grep -v \*(secondo le risposte seguenti) generano errori:

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

Sto usando:
git 1.7.4.1
ubuntu 10.04
GNU bash, versione 4.1.5 (1) -release
GNU grep 2.5.4


7
Ti prego di accettare la risposta di @Andrew!
Robert Siemer,


@GiulioCaccin La domanda riguarda anche le filiali che potrebbero non essere state unite e ho aggiornato la domanda per riflettere esplicitamente questo.
Louth,

Risposte:


384

Il sottocomando 'git branch -d' può eliminare più di un ramo. Quindi, semplificando la risposta di @ sblom ma aggiungendo un xargs critico:

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

o, ulteriormente semplificato per:

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

È importante sottolineare che, come notato da @AndrewC, l'uso git branchper gli script è sconsigliato. Per evitarlo usa qualcosa come:

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

Attenzione garantita sulle cancellazioni!

$ 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).

Questo comando riporta ancora gli stessi errori menzionati nei commenti per la risposta di seguito. error:branch 'STORY-123-Short-Description' not found.per ciascuno dei rami elencati.
Louth,

1
Per me va bene; vedi sopra con i dettagli aggiunti.
GoZoner,

1
Quindi, usando git 1.7.10 hai risolto il tuo problema o preferisci lavorare direttamente nel repository .git?
GoZoner,

1
Se ricevi un error:branch 'STORY-123-Short-Description' not found.errore, ciò è probabilmente dovuto alle impostazioni del colore git. Questo ha funzionato per me (notare l' --no-coloropzione):git branch --no-color --merged | grep -v \* | xargs git branch -D
marcok

3
L'unica risposta su SO che ho trovato che funziona. Grazie!
Kevin Suttle,

140

Ho trovato un modo migliore in un commento su questo problema su github :

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

modifica: aggiunta opzione no-color ed esclusione del ramo stabile (aggiungi altri rami secondo necessità nel tuo caso)


2
Infine, la soluzione di cui avevo bisogno
Code Whisperer,

1
Ho provato questo, ma continuo a ottenere error: branch 'my-branch-name' not found.per ogni ramo. Usando la versione 1.8.3.4 di git (Apple Git-47). Qualche idea sul perché?
wheresrhys,

prova 'git branch - master unito | grep -v master | xargs echo 'per eseguire il debug di cosa sta esattamente cercando di eliminare? non ho idee migliori ...
mBardos

2
Così. git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
Павел Тявин,

1
Ho imparato l'uso di xargs insieme a questo. Grazie
Volem,

105

L'analisi dell'output di git branchnon è consigliata e non è una buona risposta per i futuri lettori su Stack Overflow.

  1. git branchè ciò che è noto come comando di porcellana. I comandi di porcellana non sono progettati per essere analizzati a macchina e l'output può cambiare tra le diverse versioni di Git.
  2. Esistono opzioni di configurazione dell'utente che modificano l'output git branchin modo da renderne difficile l'analisi (ad esempio, la colorazione). Se un utente ha impostato color.branch, otterrai i codici di controllo nell'output, ciò provocherà error: branch 'foo' not found.se si tenta di reindirizzarlo a un altro comando. Puoi bypassarlo con il--no-color bandiera agit branch , ma chissà quali altre configurazioni utente potrebbero spezzare le cose.
  3. git branch può fare altre cose che sono noiose da analizzare, come mettere un asterisco accanto al ramo attualmente estratto

Il manutentore di git ha questo da dire sullo scripting in git branchuscita

Per scoprire qual è l'attuale ramo, gli utenti casuali / incuranti potrebbero aver scritto attorno a git branch, il che è sbagliato. Scoraggiamo attivamente contro l'uso di qualsiasi comando Porcelain, incluso git branch, negli script, perché l'output del comando è soggetto a modifiche per aiutare il caso d'uso del consumo umano.

Risposte che suggeriscono di modificare manualmente i file in .git directory (come .git / refs / head) sono allo stesso modo problematiche (invece i ref potrebbero essere in .git / pacchetto-refs o Git potrebbe cambiare il loro layout interno in futuro).

Git fornisce il for-each-ref comando per recuperare un elenco di rami.

Git 2.7.X introdurrà l' --mergedopzione in modo da poter fare qualcosa come il seguente per trovare ed eliminare tutti i rami unitiHEAD

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 precedenti, dovrai elencare tutti i rami locali e quindi testarli singolarmente per vedere se sono stati uniti (che sarà significativamente più lento e leggermente più complicato).

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

git branch --no-color 2>/dev/null?
nobar,

5
È sicuramente un miglioramento. Avrai sempre il problema di dover filtrare *, e fa cose divertenti se qualcuno lo esegue da testa staccata. Il problema principale è che git branchè un comando di porcellana, e non vi è alcuna garanzia che l'output non cambierà in alcune versioni future di git.
Andrew C

Grazie @AndrewC - questa è entrambe le risposte alla domanda sui misteriosi errori "branch not found" e fornisce una soluzione funzionante usando un comando più appropriato! 👍
Jason,

2
Come vengono identificati i comandi GIT 'Porcelain' e 'non Porcelain'?
GoZoner,

1
Probabilmente sarebbe un utile miglioramento per escludere "dev" e "master" per impostazione predefinita?
PandaWood,

66

Il modo più semplice per eliminare tutti i rami ma mantenendo altri come "sviluppo" e "padrone" è il seguente:

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

molto utile !


8
Hai resuscitato un thread vecchio di anni e pubblicato una risposta praticamente identica a uno esistente, che è difettoso e manca i cambiamenti di sicurezza che ha avuto. Questa non è una buona risposta
Andrew C,

6
Questa risposta è chiara nel piping dell'output dal ramo git, modificandolo e passando al ramo git -D. Non c'è bisogno di essere cattivi.
Pam

Questa soluzione ha funzionato per me. Cancella tutte le filiali locali.
Prad

1
Ciò non eliminerà alcun ramo contenente parole sviluppo o master come 'develop_feature' o 'master_feature'.
Django,

QUESTA È LA RISPOSTA CHE STAVO CERCANDO 👆🏻
Konrad G

62

Per eliminare ogni ramo tranne quello che hai attualmente estratto:

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

Consiglierei di passare git branch -D $ba una echo $bprima volta per assicurarsi che elimini i rami che intendi.


1
con questo comando ottengo error:branch 'a_branch_name' not found.che riesco a vedere cosa stai cercando di fare e ho giocato con il comando ma per qualche ragione a Git non sembra piacere il nome del ramo fornito ...
Louth,

hmmm. per aiutare a risolvere i problemi, sarebbe utile vedere alcuni esempi di output dagit branch --merged
sblom

i nomi delle mie filiali sono nel formatoSTORY-123-Short-Description
Louth,

e quando corri git branch --merged, ottieni un elenco con uno di quelli su ogni riga?
sblom,

1
dice letteralmente error:branch 'a_branch_name' not found.? O si lamenta di uno dei nomi delle filiali dal tuo git branchoutput sopra?
sblom,

52

Il comando seguente eliminerà tutti i rami locali tranne il ramo principale.

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

Il comando sopra

  1. elenca tutti i rami
  2. Dall'elenco ignora il ramo principale e prendi il resto dei rami
  3. elimina il ramo

4
Vorrei utilizzare git branch | grep -v "master" | xargs git branch -dprima in modo da non eliminare i rami non uniti, solo per sicurezza. Ma bella risposta!
Jonas Lomholdt,

3
Ecco una versione PowerShell,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
Jonas Lomholdt,

1
@baklazan questo funzionerebbe solo nella riga di comando di Windows 10 se hai alcuni strumenti installati. Probabilmente hai MINGW o qualche altra cosa del genere e non lo sai.
KthProg,

42

Solo una nota, vorrei aggiornare a git 1.7.10. Potresti ricevere risposte qui che non funzioneranno sulla tua versione. La mia ipotesi è che dovresti aggiungere il prefisso al nome del ramo refs/heads/.

ATTENZIONE, procedere come segue solo se è stata creata una copia della cartella di lavoro e della directory .git.

A volte vado avanti e cancello i rami da cui non voglio dirlo .git/refs/heads. Tutti questi rami sono file di testo che contengono i 40 caratteri sha-1 del commit a cui puntano. Avrai informazioni estranee nel tuo .git/configse avessi impostato il monitoraggio specifico per uno di essi. Puoi anche cancellare quelle voci manualmente.


Finalmente un'opzione semplice e pragmatica. Mi piace: D
Melvyn,

2
Questo non funzionerà se hai ref compresso o anche se a volte hai clonato da un server remoto (che ti fornirà i file compressi). Se i ref sono impacchettati, gli ref non verranno archiviati in .git / refs / head, verranno archiviati in un file chiamato "pack-refs". Vedi git-scm.com/docs/git-pack-refs .
Alexander Bird,

1
Sembra una cattiva idea rimuovere il ramo che hai verificato al momento
Moberg,

@Moberg Basta verificare prima un commit e il tuo HEAD distaccato galleggerà bene.
RomainValeri,

34

Prova il seguente comando shell:

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

Spiegazione:

  • 🛒 Ottieni tutti i rami tramite git branch | grep -v "master"comando
  • 👇 Seleziona ogni ramo con il xargscomando
  • 💦 Elimina ramo con xargs git branch -D

3
Anche se questa potrebbe essere una risposta corretta. Una riga di codice non è molto utile senza una spiegazione di cosa e come risolve la domanda originale. Fornisci i dettagli della tua risposta.
RyanNerd,

28

Per eliminare tutti i rami locali in Linux tranne quello in cui ti trovi

// hard delete

git branch -D $(git branch)

2
Questo sembra più sicuro di andare in .git e rimuovere roba.
nelsontruran,

25

Ho trovato più semplice usare solo l'editor di testo e la shell.

  1. genere git checkout <TAB> shell. Mostrerà tutte le filiali locali.
  2. Copiali in un editor di testo, rimuovi quelli che devi conservare.
  3. Sostituisci le interruzioni di riga con spazi. (In SublimeText è super facile.)
  4. Apri shell, digita git branch -D <PASTE THE BRANCHES NAMES HERE>.

Questo è tutto.


Non penso che tu possa rimuovere il ramo su cui ti trovi.
Dong Thang,

@Dong C'è un * accanto a quel ramo quindi lo rimuovi dall'elenco copiato!
Melanie,

12

Ho avuto un simile tipo di situazione e recentemente ho trovato utile il seguente comando.

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

Se vuoi mantenere più rami, allora

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

spero che questo aiuti qualcuno.


1
Bello, ma avevo bisogno di backtick per farlo funzionare - In git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` realtà penso che tu li avessi originariamente ma si sono persi nella formattazione SO.
tassinari,

10

Dalla riga di comando di Windows, elimina tutto tranne il ramo attualmente estratto utilizzando:

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

7

Se non hai bisogno di passare attraverso Git stesso, puoi anche eliminare head in .git / refs / head manualmente o a livello di programmazione. Quanto segue dovrebbe funzionare con modifiche minime in Bash:

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

Ciò eliminerà tutti i rami locali tranne il ramo principale. Poiché i tuoi rami a monte sono archiviati sotto .git / refs / telecomandi , rimarranno intatti.

Se non stai usando Bash o vuoi ricorrere a molti repository Git contemporaneamente, puoi fare qualcosa di simile con GNU find:

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

La soluzione di ricerca è probabilmente più portatile, ma i percorsi e i nomi dei file di potatura sono difficili e potenzialmente più soggetti a errori.


Freddo. Eliminazione visiva :)
sandalone,

5

Nessuna delle risposte ha soddisfatto pienamente le mie esigenze, quindi eccoci qui:

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

Ciò eliminerà tutte le filiali locali che vengono unite e che iniziano con feature/, bugfix/o hotfix/. Successivamente il telecomando a monteorigin viene eliminato il (potrebbe essere necessario inserire una password).

Funziona su Git 1.9.5.


5

Basato su una combinazione di un numero di risposte qui - se vuoi mantenere tutti i rami che esistono in remoto ma eliminare il resto , il seguente oneliner farà il trucco:

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

3

Sebbene questa non sia una soluzione a riga di comando, sono sorpreso che la GUI di Git non sia stata ancora suggerita.

Uso la riga di comando il 99% delle volte, ma in questo caso è troppo lento (da qui la domanda originale), oppure non sai cosa stai per eliminare quando fai ricorso a una manipolazione della shell lunga ma intelligente.

L'interfaccia utente risolve questo problema poiché è possibile selezionare rapidamente i rami che si desidera rimuovere ed essere ricordati di quelli che si desidera conservare, senza dover digitare un comando per ogni ramo.

Dall'interfaccia utente vai su Branch -> Elimina e Ctrl + Fai clic sui rami che desideri eliminare in modo che siano evidenziati. Se si desidera essere sicuri che vengano uniti in un ramo (come dev), in Elimina solo se uniti in impostare Ramo locale su dev. Altrimenti, impostalo su Sempre per ignorare questo controllo.

GitUI: elimina le filiali locali


1

Per PowerShell, questo funzionerà:

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

0

Il seguente script elimina i rami. Usalo e modificalo a tuo rischio, ecc. Ecc.

Sulla base delle altre risposte a questa domanda, ho finito per scrivere una sceneggiatura bash per me stesso. L'ho chiamato "gitbd" (git branch -D) ma se lo usi, puoi rinominarlo come preferisci.

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
}

Offrirà di eliminare tutti i rami che corrispondono a un argomento modello, se passato, o tutti i rami locali quando viene chiamato senza argomenti. Ti darà anche un passaggio di conferma, poiché, sai, stiamo eliminando le cose, quindi è bello.

È un po 'stupido - se non ci sono rami che corrispondono allo schema, non se ne rende conto.

Un esempio di output:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 

0

Ho scritto uno script di shell per rimuovere tutti i rami locali tranne 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

0

Le risposte sopra funzionano bene. Ecco un altro approccio quando abbiamo molti rami nel repository locale e dobbiamo eliminare molti rami tranne pochi che si trovano nella macchina locale.

Primo git branch elencherà tutte le filiali locali.

Per trasporre la colonna dei nomi dei rami in una singola riga nel file eseguendo un comando unix
git branch > sample.txt
Questo lo salverà nel file sample.txt . E corri
awk 'BEGIN { ORS = " " } { print }' sample.txt
comando nella shell. Ciò trasformerà la colonna in riga e copierà l'elenco dei nomi dei rami in una singola riga.

E poi corri
git branch -D branch_name(s).
Ciò eliminerà tutti i rami elencati presenti in locale


0

Il modo più pragmatico: assicurati di non aver lavorato senza masterimpegno, esegui il commit / push se necessario, clona una nuova copia del repository ed elimina quello precedente.


0

A questo scopo, puoi usare git-extra

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

0

Non ho grep o altri unix sulla mia scatola ma questo ha funzionato dal terminale di VSCode:

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

Uso la minuscola d in modo che non elimini i rami non uniti.

Ero anche un maestro quando l'ho fatto, quindi * masternon esiste quindi non ha tentato di eliminare il maestro.


Confermato: se non attivo master, questo comando ELIMINERÀ master.
Brett Rowberry,

-1

Assicurati di farlo prima

git fetch

Dopo aver ottenuto tutte le informazioni sui rami remoti, utilizzare il comando seguente per rimuovere ogni singolo ramo tranne il master

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
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.