Pulizia vecchi rami remoti git


694

Lavoro da due computer diversi (A e B) e memorizzo un Git Remote comune nella directory di Dropbox.

Diciamo che ho due rami, padrone e sviluppo. Entrambi stanno monitorando le loro controparti remote origin / master e origin / devel.

Ora mentre sono sul computer A, elimino lo sviluppo del ramo, sia in locale che in remoto.

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

In esecuzione git branch -asul computer A, ottengo il seguente elenco di rami.

  • maestro
  • origine / HEAD
  • origin / master

In esecuzione git fetchsul computer B, posso rimuovere il ramo di sviluppo locale con git branch -d devel, ma non riesco a rimuovere il ramo di sviluppo remoto.

git push origin :heads/devel restituisce i seguenti messaggi di errore.

errore: impossibile spingere verso destinazione non qualificata: heads / proxy3d
Il refspec di destinazione non corrisponde a un riferimento esistente sul telecomando né inizia con i riferimenti / e non siamo in grado di indovinare un prefisso basato sul riferimento sorgente.
fatale: l'estremità remota ha riattaccato inaspettatamente

git branch -a elenca ancora origine / sviluppo nei rami remoti.

Come posso ripulire i rami remoti dal computer B?


4
Mi è stato detto da qualcuno che l'ha provato, che i repository git nelle cartelle Dropbox sono un po 'fragili (ma senza ulteriori dettagli).
Thorbjørn Ravn Andersen,

5
@ ThorbjørnRavnAndersen probabilmente perché devi aspettare per assicurarti che si sincronizzi completamente ogni volta che commetti, prima di poter essere sicuro che sia sicuro da usare sull'altro computer (e anche un'altra sincronizzazione richiesta anche allora).
ataulm

Risposte:


1239

Innanzitutto, qual è il risultato git branch -asulla macchina B?

In secondo luogo, è già stato eliminato heads/develsu origin, ecco perché non è possibile eliminarlo dalla macchina B.

Provare

git branch -r -d origin/devel

o

git remote prune origin

o

git fetch origin --prune

e sentiti libero di aggiungere --dry-runalla fine della tua gitdichiarazione per vedere il risultato della sua esecuzione senza effettivamente eseguirla.

Documenti per git remote prunee git branch.


50
git remote prune originha funzionato per me => * [pruned] origin/my-old-branch
Hari Karam Singh,

126
git remote prune origin --dry-runti mostra cosa verrebbe cancellato senza farlo effettivamente.
Wolfram Arnold,

30
git fetch origin --pruneera perfetto per rimuovere i rami cancellati
Sébastien Barbieri il

10
Se hai una filiale locale che tiene traccia di un telecomando che non c'è più, questo non cancellerà nulla. Per quelli, sembra git branch -vvseguito da git branch -D branchnameed infine la prugna è il modo migliore.
Roman Starkov,

7
Puoi configurare la potatura in modo che avvenga automaticamente in pull / fetch impostando la seguente opzione:git config remote.origin.prune true
Patrick James McDougle

100

Considerare di eseguire:

git fetch --prune

Su base regolare in ciascun repository per rimuovere filiali locali che hanno seguito un ramo remoto che viene eliminato (non esiste più nel repository GIT remoto).

Questo può essere ulteriormente semplificato da

git config remote.origin.prune true

questa è per-repoun'impostazione che renderà ogni futuro potaturagit fetch or git pull automatica .

Per configurarlo per il tuo utente, puoi anche modificare il .gitconfig globale e aggiungere

[fetch]
    prune = true

Tuttavia, si consiglia di farlo utilizzando il seguente comando:

git config --global fetch.prune true

o per applicarlo a livello di sistema (non solo per l'utente)

git config --system fetch.prune true

14

Ecco lo script bash che può farlo per te. È la versione modificata di http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git script. La mia modifica consente di supportare diverse posizioni remote.

#!/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

1
Questo si è rotto su un ramo chiamato "origin / feature / mybranch", non sono sicuro del perché.
Stavros Korokithakis,

Il problema è nei due sedsecondi. Sostituisci sed 's/\(.*\)\/\(.*\)/\1/g'consed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier,

14

Questo comando "esecuzione a secco" elimina tutti i originrami uniti remoti ( ), tranne master. Puoi cambiarlo o aggiungere altri rami dopo il master: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 sembra buono, rimuovere il --dry-run. Inoltre, potresti provare prima questo su una forcella.


Bello. Il mio tweak utilizza perl invece del 1 ° xargs + awk: git branch -r --merged | origine grep | grep -v '>' | grep -v master | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin --delete
Andrew,

6

Se git branch -rmostra molti rami di tracciamento remoto che non ti interessano e desideri rimuoverli solo da locale, utilizza il seguente comando:

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

Una versione più sicura sarebbe quella di rimuovere solo quelli uniti:

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

Ciò potrebbe essere utile per progetti di grandi dimensioni, in cui non sono necessari i rami funzione di altri compagni di squadra ma ci sono molti rami di tracciamento remoto recuperati sul clone iniziale.

Tuttavia, questo passaggio da solo non è sufficiente, poiché i rami di tracciamento remoto eliminati tornerebbero al successivo git fetch.

Per interrompere il recupero di quei rami di tracciamento remoto è necessario specificare esplicitamente i ref da recuperare in .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/*

Nell'esempio di cui sopra solo recuperiamo master, develope rilasciare rami, sentiti libero di adattarsi di cui hai bisogno.


1
Grazie, il primo comando ha funzionato per me. Puoi anche recuperare solo un ramo con git fetch origin branchnameo creare un alias come ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"recuperare solo il ramo corrente (il mio preferito personale). Saluti.
GiovanyMoreno,

Forse OT ma cosa significa la -rbandiera? Vedo che xargsha un -Rargomento, ma non ho trovato nulla -r. Voglio dire, in teoria se ricordo bene come xargsfunziona, anche senza di -ressa dovrebbe funzionare.
Aldo 'xoen' Giambelluca,

Mi piace questa risposta. Un paio di note (affermando davvero l'ovvio). È possibile "visualizzare in anteprima" quali rami verranno eliminati rimuovendo l'ultima pipe e l'ultimo comando | xargs git branch -d. Inoltre, rimuovendo l' -ropzione ( --remotes) da git branch -dpuliamo solo i rami locali (il che potrebbe essere sufficiente considerando che per impostazione predefinita git branchnon mostra comunque i rami remoti).
Aldo 'xoen' Giambelluca,

Grazie! Questo era esattamente quello di cui avevo bisogno. Altre soluzioni suggeriscono di spingere le filiali locali potate sul telecomando per rimuoverle anche lì, ma ciò non aiuta quando il telecomando è stato rimosso o non esiste più. Questo approccio ha rimosso i riferimenti locali alle filiali remote a cui non ho più accesso.
cautionbug

@aldo, circa xargs -r, vale a dire --no-run-if-empty, è un'estensione GNU significa, ecco una bella spiegazione .
reno il

4

La cancellazione è sempre un compito impegnativo e può essere pericoloso !!! Pertanto, eseguire prima il comando seguente per vedere cosa accadrà:

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

In questo modo, come sopra, gitti fornirà un elenco di ciò che accadrebbe se viene eseguito il comando seguente.

Quindi eseguire il comando seguente per rimuovere tutti i rami dal repository remoto che non si trovano nel repository locale:

git push --all --prune

10
Questo comando sembra essere pericoloso ... È riuscito a eliminare ciò che volevo (e non potevo fare con almeno quattro delle risposte sopra). Ma ha anche eliminato altri quattro rami di sviluppo. Git fa assolutamente schifo ...
jww

2
Quei rami non devono essere stati nel tuo locale. Tuttavia non tutto è perduto. Git commit, Git reflog e quindi git reset --hard <checksum>. Puoi letteralmente eseguire qualsiasi commit (ovvero salvare) e altri con questo. Branch è solo un'etichetta, l'eliminazione dell'etichetta non elimina il salvataggio ... avrà sempre un checksum. Fammi sapere se posso aiutarti
Timothy LJ Stewart,

3
Ovviamente, vorrai recuperarli abbastanza rapidamente poiché il garbage collector di git alla fine rimuoverà i commit a cui non fanno riferimento i rami.
Andrew,

1
È utile aggiungere -n(esecuzione a secco) a questo comando in modo da poter visualizzare in anteprima le modifiche e, se tutto va bene, richiamarlo nuovamente senza -n.
mati865,

1
Concordo con @GuiWeinmann - Questo è troppo pericoloso, soprattutto senza un richiamo specifico per almeno eseguirlo prima in dry-run.
Vivek M. Chawla,

2

Ecco come farlo con SourceTree (v2.3.1):
1. Fai clic su Recupera
2. Seleziona "Elimina rami di rilevamento ..."
3. Premi OK
4. 😀

inserisci qui la descrizione dell'immagine


1

Dovrò aggiungere una risposta qui, perché le altre risposte non riguardano il mio caso o sono inutilmente complicate. Uso github con altri sviluppatori e voglio solo che tutti i rami locali i cui telecomandi siano stati (possibilmente uniti e) eliminati da un github PR vengano eliminati in un colpo solo dalla mia macchina. No, cose come git branch -r --mergednon coprono i rami che non sono stati uniti a livello locale, o quelli che non sono stati uniti (abbandonati) ecc., Quindi è necessaria una soluzione diversa.

Ad ogni modo, il primo passo l'ho ottenuto da altre risposte:

git fetch --prune

Una serie a secco git remote prune originsembrava che avrebbe fatto la stessa cosa nel mio caso, quindi sono andato con la versione più breve per mantenerlo semplice.

Ora, a git branch -vdovrebbe contrassegnare i rami i cui telecomandi vengono eliminati come [gone]. Pertanto, tutto quello che devo fare è:

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

Semplice come quello, elimina tutto ciò che voglio per lo scenario sopra.

La xargssintassi meno comune è che funziona anche su Mac e BSD oltre a Linux. Attenzione, questo comando non è una corsa a secco, quindi eliminerà forzatamente tutti i rami contrassegnati come [gone]. Ovviamente, essendo questo niente è andato per sempre, se vedi i rami cancellati che ricordi di voler mantenere, puoi sempre ripristinarli (il comando sopra avrà elencato il loro hash alla cancellazione, quindi un semplice git checkout -b <branch> <hash>.


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

Elimina gli stessi rami dai riferimenti locali e remoti (nel mio esempio da origin).

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.