Quali sono le differenze tra git remote prune, git prune, git fetch --prune, ecc


358

La mia situazione è questa ... qualcuno che lavora sullo stesso repository ha eliminato un ramo dal suo repository locale e remoto ...

La maggior parte delle persone che hanno chiesto informazioni su questo tipo di problema su Stack Overflow o su altri siti hanno il problema delle filiali che continuano a essere visualizzate nella lista delle filiali di monitoraggio remoto git branch -ain basso:

* master
  develop
  feature_blah
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah
  remotes/origin/random_branch_I_want_deleted

Tuttavia, nella mia situazione il ramo che non dovrebbe essere lì, è locale:

* master
  develop
  feature_blah
  random_branch_I_want_deleted
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah

Quando eseguo una delle seguenti operazioni, non viene rimosso localmente:

$ git prune

Ho anche provato:

$ git remote prune origin
$ git fetch --prune

Altre informazioni utili: quando controllo git remote show originquesto è come appare:

* remote origin
Fetch URL: utilities:homeconnections_ui.git
Push  URL: utilities:homeconnections_ui.git
HEAD branch: master
Remote branches:
 master                        tracked
 develop                       tracked
 feature_blah                  tracked
 other123                      tracked
 other444                      tracked
 other999                      tracked
Local branches configured for 'git pull':
 develop                      merges with remote develop
 feature_blah                 merges with remote other999
 master                       merges with remote master
 random_branch_I_want_deleted merges with remote random_branch_I_want_deleted
Local refs configured for 'git push':
 develop         pushes to develop     (local out of date)
 master          pushes to master      (up to date)
 feature_blah    pushes to feature_blah(up to date)

Si noti che è solo nella sezione intitolata Local branches configured for 'git pull':

Perché?


git branch -d the_local_branch
krsteeve,

1
Grazie, ma sono solo curioso di sapere perché potrebbe essere successo.
gogogadgetinternet,

C'era una sottile differenza nel trattare con la gerarchia dei rami ( x/y): è stato corretto (vedi la mia risposta di seguito )
VonC,

Risposte:


665

Non ti biasimo per esserti frustrato per questo. Il modo migliore di guardare è questo. Esistono potenzialmente tre versioni di ogni filiale remota:

  1. Il ramo effettivo sul repository remoto
    (ad es. Repository remoto su https://example.com/repo.git , refs/heads/master)
  2. La tua istantanea di quel ramo localmente (archiviata sotto refs/remotes/...)
    (es. Repo locale, refs/remotes/origin/master)
  3. E una filiale locale che potrebbe tenere traccia della filiale remota
    (ad esempio, repository locale, refs/heads/master)

Cominciamo con git prune. Ciò rimuove gli oggetti a cui non viene più fatto riferimento, non rimuove i riferimenti. Nel tuo caso, hai una filiale locale. Ciò significa che esiste un random_branch_I_want_deletedriferimento denominato che fa riferimento ad alcuni oggetti che rappresentano la storia di quel ramo. Quindi, per definizione, git prunenon verrà rimosso random_branch_I_want_deleted. Davvero, git pruneè un modo per eliminare i dati che si sono accumulati in Git ma a cui non fa riferimento nulla. In generale, non influisce sulla vista di alcun ramo.

git remote prune origined git fetch --pruneentrambi operano su riferimenti in refs/remotes/...(farò riferimento a questi come riferimenti remoti). Non influisce sulle filiali locali. La git remoteversione è utile se si desidera rimuovere solo riferimenti remoti in un determinato telecomando. Altrimenti, i due fanno esattamente la stessa cosa. Quindi, in breve, git remote prunee git fetch --pruneoperare sul numero 2 sopra. Ad esempio, se hai eliminato un ramo usando la GUI di git web e non vuoi che venga più visualizzato nella tua lista di rami locale ( git branch -r), allora questo è il comando che dovresti usare.

Per rimuovere un ramo locale, dovresti usare git branch -d(o -Dse non è unito da nessuna parte). FWIW, non esiste un comando git per rimuovere automaticamente i rami di tracciamento locali se scompare un ramo remoto.


22
Questo fa un lavoro migliore nell'affrontare la domanda generale spiegando le differenze pertinenti. Risponde anche ad ulteriori domande che ho avuto da quello sopra.
gogogadgetinternet,

14
Questo comando mostrerà un elenco di tutti i rami locali che non hanno un ramo remoto corrispondente. È possibile tubo di questo xargs git branch -D, ma è da notare che eventuali nuove filiali che hai creato, ma mai trasmesso al server saranno eliminati, in modo da procedere con cautela: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
Jason Walton

4
@Seed No non lo fa. :-( Elimina solo i riferimenti di tracciamento remoto locale. Ho appena ricontrollato questo con la versione 2.7.0.
John Szakmeister

1
@ BlueRaja-DannyPflughoeft Stai attento con questo approccio. Ad esempio, a seconda di come esegui i tuoi rami stabili, potrebbero sembrare uniti nel ramo principale e finiresti per rimuoverli. Non è una grande perdita qui poiché non li stai rimuovendo dal server, ma se avessi una configurazione speciale impostata per esso, andrebbe persa quando il ramo viene eliminato.
John Szakmeister,

1
@Cloud Non del tutto vero. I riferimenti possono essere compressi (vedere il packed-refsfile .gitnell'area), quindi non è necessariamente una semplice eliminazione tramite Esplora file. Meglio usare i comandi per assicurarsi che entrambi siano curati correttamente.
John Szakmeister,

55

git remote prunee git fetch --prunefai la stessa cosa: cancellare i riferimenti ai rami che non esistono sul telecomando, come hai detto. Il secondo comando si collega al telecomando e recupera i suoi rami correnti prima della potatura.

Tuttavia, non tocca le filiali locali che hai estratto, che puoi semplicemente eliminare

git branch -d  random_branch_I_want_deleted

Sostituisci -dcon -Dse il ramo non viene unito altrove

git prune fa qualcosa di diverso, elimina gli oggetti irraggiungibili, quei commit che non sono raggiungibili in nessun ramo o tag e quindi non sono più necessari.


1
So che sembra ovvio, ma git prunecerca non solo rami e tag, ma anche tutti gli altri riferimenti.

Quindi, nel mio caso, perché Git potare non funziona? Perché non importa delle filiali locali, ma riferimenti remoti? Grazie per le informazioni concise.
gogogadgetinternet,

@hvd che tipo di ref ci sono oltre a rami e tag?
CharlesB,

@gogogadgetinternet sì, esattamente. (supponendo che volevi dire git remote prune)
CharlesB,

4
IMO la convenzione di denominazione git dell'uso di "prugna" sia per la raccolta di oggetti che per la pulizia di riferimento è il punto in cui si crea la confusione. Ma questo è solo uno dei tanti enigmi dell'interfaccia utente, in git. :-)
torek,

14

Nel caso in cui qualcuno fosse interessato. Ecco uno script di shell rapido che rimuoverà tutti i rami locali che non vengono tracciati in remoto. Un avvertimento: questo eliminerà qualsiasi ramo che non viene monitorato da remoto, indipendentemente dal fatto che sia stato unito o meno.

Se vedete qualche problema con questo, per favore fatemi sapere e lo risolverò (ecc. Ecc.)

Salvalo in un file chiamato git-rm-ntb(chiamalo comunque) PATHed esegui:

git-rm-ntb <remote1:optional> <remote2:optional> ...

clean()
{
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  RBRANCHES=()
  while read REMOTE; do
    CURRBRANCHES=($(git ls-remote $REMOTE | awk '{print $2}' | grep 'refs/heads/' | sed 's:refs/heads/::'))
    RBRANCHES=("${CURRBRANCHES[@]}" "${RBRANCHES[@]}")
  done < <(echo "$REMOTES" )
  [[ $RBRANCHES ]] || exit
  LBRANCHES=($(git branch | sed 's:\*::' | awk '{print $1}'))
  for i in "${LBRANCHES[@]}"; do
    skip=
    for j in "${RBRANCHES[@]}"; do
      [[ $i == $j ]] && { skip=1; echo -e "\033[32m Keeping $i \033[0m"; break; }
    done
    [[ -n $skip ]] || { echo -e "\033[31m $(git branch -D $i) \033[0m"; }
  done
}

clean $@

Grazie! Bel tocco con l'output colorato ;-)
BVengerov

2
$ (Git branch -d $ i) non sarebbe più sicuro eliminare solo i rami uniti?
user2012677

Così utile grazie mille !!!
Robin Hartland,

Le opzioni più sicure sono discussi in stackoverflow.com/questions/7726949/...
Michael Freidgeim

13

Si noti che una differenza tra git remote --prunee git fetch --pruneviene risolta, con commit 10a6cc8 , di Tom Miller ( tmiller) (per git 1.9 / 2.0, Q1 2014):

Quando abbiamo un ramo di tracciamento remoto chiamato " frotz/nitfol" da un precedente recupero, e l'upstream ora ha un ramo chiamato "** frotz " **, fetchnon riuscirebbe a rimuovere " frotz/nitfol" con un " git fetch --prune" dall'upstream .
git informerebbe l'utente di usare " git remote prune" per risolvere il problema.

Quindi: quando un repository a monte ha un ramo ("frotz") con lo stesso nome di una gerarchia di rami ("frotz / xxx", una possibile convenzione di denominazione dei rami ), ci riusciva git remote --prune(nel ripulire il ramo di tracciamento remoto dal proprio repository) , ma git fetch --prunestava fallendo.

Non più:

Cambia il modo in cui " fetch --prune" funziona spostando l'operazione di potatura prima dell'operazione di recupero.
In questo modo, invece di avvisare l'utente di un conflitto, lo risolve automaticamente.

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.