Elenca tutte le filiali locali senza un telecomando


93

Problema: voglio un modo per eliminare tutti i rami locali che ho che non hanno un telecomando. È abbastanza facile inserire i nomi dei rami in un git branch -D {branch_name}, ma come ottengo quell'elenco in primo luogo?

Per esempio:

Creo un nuovo ramo senza telecomando:

$ git co -b no_upstream

Elenco tutti i miei rami e ce n'è solo uno con un telecomando

$ git branch -a
master
* no_upstream
remotes/origin/HEAD -> origin/master
remotes/origin/master

Quale comando posso eseguire per ottenere no_upstreamuna risposta?

Posso correre git rev-parse --abbrev-ref --symbolic-full-name @{u}e questo mostrerà che non ha telecomando:

$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Ma poiché si tratta di un errore, non mi consente di usarlo o di collegarlo ad altri comandi. Ho intenzione di usarlo come alias di uno script di shell git-delete-unbranchedo forse per creare una gemma super semplicegit-branch-delete-orphans



Risposte:


105

Recentemente ho scoperto git branch -vvqual è la versione "molto dettagliata" del git branchcomando.

Produce i rami insieme ai rami remoti se esistono, nel seguente formato:

  25-timeout-error-with-many-targets    206a5fa WIP: batch insert
  31-target-suggestions                 f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link                      b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
  65-digest-double-publish              2de4150 WIP: publishing-state

Una volta che hai questo output ben formattato, è facile come collegarlo cute awkottenere il tuo elenco:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'

Risultati nel seguente output:

25-timeout-error-with-many-targets
65-digest-double-publish

La cutparte normalizza semplicemente i dati rimuovendo i primi due caratteri (inclusi *) dall'output prima di passarli a awk.

La awkporzione stampa la prima colonna se non è presente una parentesi quadra nella terza colonna.

Bonus: crea un alias

Semplifica l'esecuzione creando un alias nel tuo .gitconfigfile globale (o ovunque):

[alias]
  local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'

Importante: la barra rovesciata deve essere preceduta da caratteri di escape nell'alias, altrimenti avrai un file gitconfig non valido.

Bonus: filtro remoto

Se per qualche motivo disponi di più telecomandi di tracciamento per rami diversi, è abbastanza facile specificare quale telecomando vuoi confrontare. Basta aggiungere il nome remoto al pattern awk. Nel mio caso, è origincosì che posso farlo:

git branch -vv | cut -c 3- | awk '$3 !~/\[origin/ { print $1 }'

che cos'è WIP:comunque ..? non è quello che crea un comando stash ..?
igrek

@igrek Questo è solo un prefisso che ho usato nel messaggio di commit. Niente di specifico per git.
Jeremy Baker

quando lo faccio git branch -vv, anche se esiste un ramo remoto e corrisponde al mio ramo locale, non [origin/branch-name]vedrei il risultato accanto. Ho dovuto diffdue elenchi di filiali per capire effettivamente cosa fosse solo locale.
ryantuck

git branch -vv | grep -v origin/è abbastanza per me
niente panico

2
Non mancano i rami remoti contrassegnati gone?
Reid

36

git branch (senza opzioni) elenca solo i rami locali, ma non sai se stanno monitorando un ramo remoto o meno.

Di solito quei rami locali dovrebbero essere cancellati una volta uniti in master(come visto in questo numero di git-sweep ):

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

Questo non è completo come vuoi, ma è un inizio.

Con --merged, verranno elencati solo i rami uniti nel commit nominato (cioè i rami i cui commit di punta sono raggiungibili dal commit nominato) saranno elencati.


1
Per includere anche rami remoti senza un ramo locale, usa git branch -a --merged.
Acumenus

21

Ho un problema simile. Desidero rimuovere tutti i rami locali che stavano monitorando i rami remoti che ora sono stati eliminati. Trovo che git remote prune originnon fosse sufficiente per rimuovere i rami che voglio sparire. Una volta che il telecomando è stato eliminato, voglio che anche il locale scompaia. Ecco cosa ha funzionato per me:

Dal 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 aggiungerlo facilmente 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 : ho cambiato -din -Dnella mia configurazione attuale, perché non voglio sentire Git lamentarsi dei rami non uniti. Si può volere questa funzionalità pure. Se è così, usa semplicemente -Dinvece che -dalla fine di quel comando.

Inoltre, FWIW, il tuo file di configurazione globale sarebbe quasi sempre ~/.gitconfig.

(OS X Fix)

Come scritto, questo non funziona su OS X a causa dell'uso di xargs -r (grazie, Korny ).

Il -rè quello di prevenire xargsl'esecuzione git branch -dsenza un nome del ramo, che si tradurrà in un messaggio di errore "fatal: branch name required ". Se non ti dispiace il messaggio di errore, puoi semplicemente rimuovere l' -rargomento su xargse sei pronto.

Tuttavia, se non vuoi vedere un messaggio di errore (e davvero, chi potrebbe biasimarti), allora avrai bisogno di qualcos'altro che controlli la presenza di una pipe vuota. Se potresti essere in grado di usare ifne da moreutils . Dovresti inserire ifneprima xargs, che interromperà l' xargsesecuzione con dati vuoti. NOTA :ifne considera tutto ciò che non è vuoto, incluse le righe vuote, quindi potresti ancora vedere quel messaggio di errore. Non l'ho testato su OS X.

Ecco quella git configlinea con ifne:

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

1
È possibile convertirlo in un comando "git config --global ..."? Dal punto di vista delle istruzioni / come-wiki-for-dummies è facile passare avanti invece di dire "Trova i tuoi file git config, usa l'editor per modificarli, quindi esegui i comandi"
Kannan Ekanath


Buono a sapersi. Non so quale sarebbe l'opzione "no run if empty" per OSX.
Karl Wilbur

18

Modifica tardiva:

È meglio

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

Su GNU / qualsiasi cosa

for b in `git branch|sed s,..,,`; do
    git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done

Se fosse probabile più di una manciata di rami, ci sarebbero modi migliori, utilizzando comm -23sull'output di git branch|sed|sorte git config -l|sed|sort.


1
@nmr s / git. * Q1 / test $ (git config --get branch. $ b.remote | sed q | wc -1) = 1 /
jthill

15

Questo funziona per me:

git branch -vv | grep -v origin

(se il tuo telecomando ha un nome diverso da origin, sostituiscilo).

Questo elencherà tutti i rami che non stanno monitorando un telecomando, che suona come quello che stai cercando.


2
Questo elencherà i rami che avevano un telecomando ma non lo fanno più anche se corri git fetch --prune.
RusinaRange

2
IMO, è meglio cercare ": gone]" invece di filtrare "origin"
fiorentino il

5

Sintetizzo il mio comando Git per ottenere i origin/***: gonerami:

git remote prune origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d

git remote prune origin && git branch -vv stamperà i rami in modalità dettagliata.

cut -c 3- rimuoverà i primi caratteri.

grep ': gone]'stamperà solo i rami remoti andati .

awk '{print $1}' stamperà il nome del ramo.

xargs -n1 -r echo git branch -dstamperà il git branch -dcomando per rimuovere i rami (-n1 gestirà un comando alla volta, -r per evitare di emettere il comando se non è presente alcun ramo).

SUGGERIMENTO: rimuovi il comando "echo" per eseguire i comandi invece di stampare solo, l'ho lasciato nel comando per controllare i comandi prima di inviare a git.

SUGGERIMENTO 2: emetti git branch -Dse e solo se sei sicuro di voler rimuovere i rami non uniti


da questo ho fatto il mio git
fiorentino il

2
Questa è di gran lunga la soluzione più pulita che ho trovato, bello! Non ho mai passato il tempo a studiare awk, non sapevo che tu potessi farlo.
adamjc

1
Questo è l'unico che ha ottenuto tutti i rami che sono stati uniti, eliminati o in altro modo localmente per me.
Max

2

Ecco qualcosa che ho usato in PowerShell con commenti per spiegare cosa sta facendo. Nel tentativo di chiarire cosa sta succedendo, non ho utilizzato alcun comando di PowerShell abbreviato (alias). Sentiti libero di comprimerlo al livello di criptaggio desiderato :)

$verboseList = @(git branch -vv)
foreach ($line in $verboseList)
{
    # Get the branch name
    $branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
    # Check if the line contains text to indicate if the remote is deleted
    $remoteGone = $line.Contains(": gone]")
    # Check if the line does not contain text to indicate it is a tracking branch (i.e., it's local)
    $isLocal = !($line.Contains("[origin/"))
    if ($remoteGone -or $isLocal)
    {
        # Print the branch name
        $branch
    }
}

0

Combinando alcune delle risposte esistenti:

[alias]
        branch-local = !git branch -vv | cut -c 3- | egrep '([0-9a-f]{7} [^[])|(: gone\\])' | sed -E 's/(^.+[0-9a-f]{7} (\\[.+\\])?).*$/\\1/'

Per esempio:

$ git branch-local
autogen_autoreconf      fcfb1c6 [github/autogen_autoreconf: gone]
autotools_documentation 72dc477 [github/autotools_documentation: gone]
cray-mpich-messy        2196f4b
epel-sphinx             cfda770
lammps                  07d96a7 [github/lammps: gone]
lark-error              9ab5d6c [github/lark-error: gone]
no-root2                c3894d1
openmpi-cray            69326cf [github/openmpi-cray: gone]
shellcheck-cleanup      40d90ec
travis-python36         cde072e
update_vagrant_default  4f69f47 [github/update_vagrant_default: gone]
web-docs                e73b4a8

0

Nessuna delle risposte esistenti sembra funzionare per me.

Ecco la mia soluzione per elencare le filiali locali che non sono anche remote

comm -13 <(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) <(git branch | cut -c 3-)

Ed ecco una spiegazione di come funziona:

  1. Considera l'elenco di tutti i rami remoti (senza "origine /" o spazi iniziali) git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-

  2. Considera l'elenco di tutte le filiali locali (senza asterischi o spazi iniziali) git branch | cut -c 3-

  3. Confronta questi due elenchi e mostrami qualcosa nell'elenco 2 (i miei rami locali) che non è nell'elenco 1 (l'elenco dei rami remoti) comm -13 <(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) <(git branch | cut -c 3-)

comm può prendere una combinazione dei flag -1, -2 e -3 che indicano da quale file sopprimere le righe (unico per il file 1, unico per il file 2 o comune a entrambi)

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.