Care sunt diferențele dintre git remote prune, git prune, git fetch –prune, etc. (Programare, Git, Ramură La Distanță)

gogogadgetinternet a intrebat.

Situația mea este următoarea… cineva care lucrează la același repo a șters o ramură din repo-ul său local & remote repo…

Cei mai mulți oameni care au întrebat despre acest tip de problemă pe Stack Overflow, sau alte site-uri au problema ramurilor care încă apar în lista de ramuri de urmărire la distanță git branch -a în partea de jos:

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

Cu toate acestea, în situația MEA, ramura care nu ar trebui să fie acolo, este locală:

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

Când fac oricare dintre următoarele, nu este eliminată local:

$ git prune

De asemenea, am încercat:

$ git remote prune origin
$ git fetch --prune

Mai multe informații utile: Când verific git remote show origin așa arată:

* 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)

Observați că este doar în secțiunea intitulată Local branches configured for 'git pull':

De ce?

Comentarii

  • git branch -d the_local_branch –  > Por krsteeve.
  • Mulțumesc, dar sunt doar curios de ce s-ar fi putut întâmpla. –  > Por gogogadgetinternet.
  • A existat o diferență subtilă atunci când se ocupa de ierarhia ramurilor (x/y): a fost reparată (vezi răspunsul meu de mai jos) –  > Por VonC.
4 răspunsuri
John Szakmeister

Nu te condamn pentru că ești frustrat din această cauză. Cel mai bun mod de a privi este acesta. Există potențial trei versiuni ale fiecărei ramuri de la distanță:

  1. Ramura reală de pe depozitul la distanță
    (de exemplu, repo-ul la distanță la https://example.com/repo.git, refs/heads/master)
  2. Imaginea instantanee a ramurii respective la nivel local (stocată sub refs/remotes/...)
    (de exemplu, repo local, refs/remotes/origin/master)
  3. Și o ramură locală care ar putea urmări ramura de la distanță
    (de exemplu, repo local, refs/heads/master)

Să începem cu git prune. Aceasta elimină obiecte care nu mai fac obiectul unei referințe, dar nu elimină referințele. În cazul dumneavoastră, aveți o ramură locală. Asta înseamnă că există o referință numită random_branch_I_want_deleted care se referă la unele obiecte care reprezintă istoricul acelei ramuri. Deci, prin definiție, git prune nu va elimina random_branch_I_want_deleted. Într-adevăr, git prune este o modalitate de a șterge datele care s-au acumulat în Git, dar care nu sunt menționate de nimic. În general, nu vă afectează vizualizarea niciunei ramuri.

git remote prune origin și git fetch --prune ambele operează asupra referințelor sub refs/remotes/... (mă voi referi la acestea ca referințe la distanță). Nu afectează ramurile locale. Adresa git remote este utilă dacă doriți să eliminați doar referințele la distanță sub o anumită distanță. În rest, cele două fac exact același lucru. Deci, pe scurt, git remote prune și git fetch --prune operează cu numărul 2 de mai sus. De exemplu, dacă ați șters o ramură folosind GUI web git și nu doriți ca aceasta să mai apară în lista locală de ramuri (git branch -r), atunci aceasta este comanda pe care ar trebui să o utilizați.

Pentru a elimina o ramură locală, trebuie să utilizați git branch -d (sau -D dacă nu este fuzionată nicăieri). FWIW, nu există nicio comandă git care să elimine automat ramurile locale de urmărire dacă dispare o ramură de la distanță.

Comentarii

    25

  • Acest lucru face o treabă mai bună de abordare a întrebării generale prin explicarea diferențelor pertinente. De asemenea, răspunde la întrebări suplimentare pe care le aveam de la cea de mai sus. –  > Por gogogadgetinternet.
  • 15

  • Această comandă va afișa o listă a tuturor ramurilor locale care nu au o ramură la distanță corespunzătoare. Puteți puteți accesa trimiteți această comandă la xargs git branch -D, dar rețineți că toate ramurile noi pe care le-ați creat, dar nu le-ați trimis niciodată pe server, vor fi șterse, așa că aveți grijă: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' –  > Por Jason Walton.
  • @Seed Nu, nu se șterge. 🙁 Se șterg doar referințele de urmărire la distanță locale. Tocmai am verificat de două ori acest lucru cu versiunea 2.7.0. –  > Por John Szakmeister.
  • @BlueRaja-DannyPflughoeft Aveți grijă cu această abordare. De exemplu, în funcție de modul în care vă faceți ramurile stabile, acestea pot părea să fie îmbinate în ramura principală, iar dumneavoastră ați ajunge să le eliminați. Nu este o mare pierdere aici, deoarece nu le eliminați de pe server, dar dacă ați avut vreo configurație specială pe care ați setat-o pentru ea, atunci aceasta ar fi pierdută atunci când ramura este ștearsă. –  > Por John Szakmeister.
  • @Cloud Nu este în întregime adevărat. Referințele pot fi împachetate (a se vedea packed-refs în fișierul .git zonă), deci nu este neapărat o chestiune simplă de a le șterge prin intermediul exploratorului de fișiere. Este mai bine să folosiți comenzile pentru a vă asigura că ambele sunt rezolvate corect. –  > Por John Szakmeister.
CharlesB

git remote prune și git fetch --prune fac același lucru: ștergând referințele la ramurile care nu există pe remote, așa cum ați spus. A doua comandă se conectează la distanță și preia ramurile sale curente înainte de tăiere.

Cu toate acestea, nu se atinge de ramurile locale pe care le-ați verificat, pe care le puteți șterge pur și simplu cu

git branch -d  random_branch_I_want_deleted

Înlocuiește -d prin -D dacă ramura nu este fuzionată în altă parte

git prune face ceva diferit, elimină obiectele inaccesibile, acele angajamente care nu pot fi accesate în nicio ramură sau etichetă și care, prin urmare, nu mai sunt necesare.

Comentarii

  • Știu că pare evident, dar git prune caută nu numai ramurile și etichetele, ci și toate celelalte referințe. – user743382
  • Deci, în cazul meu, de ce nu ar funcționa git prune? Pentru că nu-i pasă de ramurile locale, ci de referințele la distanță? Mulțumesc pentru informațiile concise. –  > Por gogogadgetinternet.
  • @hvd ce fel de referințe există, în afară de ramuri și etichete?  > Por CharlesB.
  • @gogogogadgetinternet da, exact. (presupunând că te-ai referit la git remote prune) –  > Por CharlesB.
  • IMO convenția de denumire git de a folosi „prune” atât pentru colectarea de obiecte și curățare a referințelor este locul unde apare confuzia. Dar aceasta este doar una dintre multele nedumeriri ale interfeței de utilizare, în git. 🙂 –  > Por torek.
D.Mill

În cazul în care cineva ar fi interesat. Iată un script shell rapid care va elimina toate ramurile locale care nu sunt urmărite de la distanță. Un cuvânt de precauție: Acest lucru va elimina orice ramură care nu este urmărită de la distanță, indiferent dacă a fost sau nu fuzionată.

Dacă vedeți vreo problemă cu acest lucru, vă rog să mă anunțați și o voi rezolva (etc. etc.).

Salvați-o într-un fișier numit git-rm-ntb (numiți-l cum vreți) pe PATH și rulați:

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

clean()
{
  REMOTES="[email protected]";
  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 "33[32m Keeping $i 33[0m"; break; }
    done
    [[ -n $skip ]] || { echo -e "33[31m $(git branch -D $i) 33[0m"; }
  done
}

clean [email protected]

Comentarii

  • Mulțumesc! Frumoasă atingere cu ieșirea colorată 😉 –  > Por BVengerov.
  • Nu ar fi mai sigur ca $(git branch -d $i) să șteargă doar ramurile fuzionate? –  > Por user2012677.
  • Opțiunile mai sigure sunt discutate în stackoverflow.com/questions/7726949/… –  > Por Michael Freidgeim.
VonC

Rețineți că o diferență între git remote --prune și git fetch --prune este în curs de corectare, cu commit 10a6cc8, de către Tom Miller (tmiller) (pentru git 1.9/2.0, Q1 2014):

Atunci când avem o ramură de urmărire la distanță numită „frotz/nitfol” de la o preluare anterioară, iar în upstream există acum o ramură numită „**frotz„**, fetch nu ar reuși să elimine „frotz/nitfol” cu un „git fetch --prune” din fluxul ascendent.
git ar informa utilizatorul să folosească „git remote prune” pentru a rezolva problema.

Deci: când un repo din amonte are o ramură („frotz”) cu același nume ca și o ramură ierarhia ramurii („frotz/xxx”, o posibilă convenție de denumire a ramurii), git remote --prune reușea (în curățarea ramurii de urmărire la distanță din repo-ul tău), dar git fetch --prune a eșuat.

Acum nu mai este așa:

Schimbați modul în care „fetch --prune” funcționează prin mutarea operațiunii de curățare înaintea operațiunii de preluare.
În acest fel, în loc să avertizeze utilizatorul despre un conflict, îl rezolvă automat.