Was sind die Unterschiede zwischen Git Remote Prune, Git Prune, Git Fetch - Prune usw.

358

Meine Situation ist folgende: Jemand, der am selben Repo arbeitet, hat einen Zweig aus seinem lokalen und Remote-Repo gelöscht ...

Die meisten Personen, die bei Stack Overflow oder anderen Websites nach solchen Problemen gefragt haben, haben das Problem, dass Zweige weiterhin in ihrer Liste git branch -ader Fernverfolgungszweige unten angezeigt werden:

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

In MEINER Situation ist die Niederlassung, die nicht vorhanden sein sollte, lokal:

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

Wenn ich eine der folgenden Aktionen ausführe, wird sie lokal nicht entfernt:

$ git prune

Ich habe auch versucht:

$ git remote prune origin
$ git fetch --prune

Weitere nützliche Informationen: Wenn ich das überprüfe, git remote show originsieht es so aus:

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

Beachten Sie, dass es nur im Abschnitt mit dem Titel ist Local branches configured for 'git pull':

Warum?

gogogadgetinternet
quelle
git branch -d the_local_branch
krsteeve
1
Danke, aber ich bin nur neugierig, warum es passiert sein könnte.
Gogogadgetinternet
Es gab einen subtilen Unterschied beim Umgang mit x/y
Zweighierarchien

Antworten:

664

Ich beschuldige Sie nicht, darüber frustriert zu sein. Der beste Weg, dies zu betrachten, ist dies. Es gibt möglicherweise drei Versionen jedes Remote-Zweigs:

  1. Der eigentliche Zweig im Remote-Repository
    (z. B. Remote-Repo unter https://example.com/repo.git , refs/heads/master)
  2. Ihr Schnappschuss dieses Zweigs lokal (gespeichert unter refs/remotes/...)
    (z. B. lokales Repo, refs/remotes/origin/master)
  3. Und eine lokale Niederlassung, die möglicherweise die entfernte Niederlassung verfolgt
    (z. B. lokales Repo refs/heads/master).

Beginnen wir mit git prune. Dadurch werden Objekte entfernt , auf die nicht mehr verwiesen wird, und es werden keine Verweise entfernt. In Ihrem Fall haben Sie eine lokale Niederlassung. Das heißt, es gibt eine Referenz mit dem Namen random_branch_I_want_deleted, die sich auf einige Objekte bezieht, die den Verlauf dieses Zweigs darstellen. git pruneWird also per Definition nicht entfernt random_branch_I_want_deleted. Dies git pruneist eine Möglichkeit, Daten zu löschen, die sich in Git angesammelt haben, auf die jedoch von nichts verwiesen wird. Im Allgemeinen hat dies keine Auswirkungen auf Ihre Ansicht von Zweigen.

git remote prune originund git fetch --prunebeide arbeiten mit Referenzen unter refs/remotes/...(ich werde diese als Fernreferenzen bezeichnen). Lokale Niederlassungen sind davon nicht betroffen. Die git remoteVersion ist nützlich, wenn Sie nur Remote-Referenzen unter einer bestimmten Remote entfernen möchten. Ansonsten machen die beiden genau das Gleiche. Also, kurz gesagt, git remote pruneund git fetch --prunearbeiten Sie mit Nummer 2 oben. Wenn Sie beispielsweise einen Zweig über die Git-Web-GUI gelöscht haben und nicht mehr in Ihrer lokalen Zweigliste angezeigt werden sollen ( git branch -r), sollten Sie diesen Befehl verwenden.

Um einen lokalen Zweig zu entfernen, sollten Sie verwenden git branch -d(oder -Dwenn er nirgendwo zusammengeführt wird). FWIW, es gibt keinen git-Befehl zum automatischen Entfernen der lokalen Verfolgungszweige, wenn ein entfernter Zweig verschwindet.

John Szakmeister
quelle
22
Dies kann die Gesamtfrage besser beantworten, indem die relevanten Unterschiede erläutert werden. Es beantwortet auch zusätzliche Fragen, die ich von der oben genannten hatte.
Gogogadgetinternet
14
Dieser Befehl zeigt eine Liste aller lokalen Zweige an, die keinen entsprechenden Remote-Zweig haben. Sie könnten dies xargs git branch -Dweiterleiten, aber beachten Sie, dass alle neuen Zweige, die Sie erstellt, aber nie auf den Server verschoben haben, gelöscht werden. Gehen Sie also vorsichtig vor: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
Jason Walton
4
@Seed Nein, tut es nicht. :-( Es löscht nur die lokalen Fernverfolgungsreferenzen. Ich habe dies gerade mit Version 2.7.0 überprüft.
John Szakmeister
1
@ BlueRaja-DannyPflughoeft Sei vorsichtig mit diesem Ansatz. Abhängig davon, wie Sie Ihre stabilen Zweige erstellen, scheinen sie beispielsweise mit dem Hauptzweig zusammengeführt zu sein, und Sie würden sie am Ende entfernen. Dies ist hier kein großer Verlust, da Sie sie nicht vom Server entfernen. Wenn Sie jedoch eine spezielle Konfiguration dafür festgelegt haben, geht diese verloren, wenn der Zweig gelöscht wird.
John Szakmeister
1
@ Cloud Nicht ganz richtig. Referenzen können gepackt werden (siehe packed-refsDatei in der .gitUmgebung), daher ist es nicht unbedingt einfach, sie über den Datei-Explorer zu löschen. Verwenden Sie besser die Befehle, um sicherzustellen, dass beide korrekt ausgeführt werden.
John Szakmeister
55

git remote pruneund git fetch --prunemachen Sie dasselbe: Löschen Sie die Refs in den Zweigen, die auf der Fernbedienung nicht vorhanden sind, wie Sie sagten. Der zweite Befehl stellt eine Verbindung zur Fernbedienung her und ruft deren aktuelle Zweige ab, bevor er beschnitten wird.

Es berührt jedoch nicht die lokalen Zweige, die Sie ausgecheckt haben und mit denen Sie einfach löschen können

git branch -d  random_branch_I_want_deleted

Ersetzen -ddurch, -Dwenn der Zweig nicht an anderer Stelle zusammengeführt wird

git prune Wenn Sie etwas anderes tun, werden nicht erreichbare Objekte gelöscht, die Commits, die in keinem Zweig oder Tag erreichbar sind und daher nicht mehr benötigt werden.

CharlesB
quelle
1
Ich weiß, es scheint offensichtlich, git prunesucht aber nicht nur nach Zweigen und Tags, sondern auch nach allen anderen Refs.
Warum sollte Git Prune in meinem Fall nicht funktionieren? Weil es nicht um lokale Niederlassungen geht, sondern um Remote-Referenzen? Danke für die prägnanten Infos.
Gogogadgetinternet
@hvd Welche Art von Refs gibt es außer Zweigen und Tags?
CharlesB
@gogogadgetinternet ja genau. ( git remote prune
Angenommen
4
IMO, die Git-Namenskonvention, "Prune" sowohl für die Objekterfassung als auch für die Referenzbereinigung zu verwenden, setzt die Verwirrung ein. Aber das ist nur eines von vielen UI-Rätseln in Git. :-)
Torek
14

Für den Fall, dass jemand interessiert wäre. Hier ist ein schnelles Shell-Skript, mit dem alle lokalen Zweige entfernt werden, die nicht remote verfolgt werden. Ein Wort der Vorsicht: Dadurch werden alle Zweige entfernt, die nicht remote verfolgt werden, unabhängig davon, ob sie zusammengeführt wurden oder nicht.

Wenn ihr irgendwelche Probleme damit seht, lasst es mich bitte wissen und ich werde es beheben (usw. usw.)

Speichern Sie es in einer Datei mit dem Namen git-rm-ntb(nennen Sie es wie auch immer) PATHund führen Sie Folgendes aus:

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 $@
D. Mill
quelle
Vielen Dank! Netter Touch mit der farbigen Ausgabe ;-)
BVengerov
2
Wäre $ (git branch -d $ i) nicht sicherer, nur zusammengeführte Zweige zu löschen?
user2012677
So hilfreich, vielen Dank !!!
Robin Hartland
Die sichereren Optionen werden unter stackoverflow.com/questions/7726949/…
Michael Freidgeim
13

Beachten Sie, dass ein Unterschied zwischen git remote --pruneund git fetch --prunemit Commit 10a6cc8 von Tom Miller ( tmiller) behoben wird (für Git 1.9 / 2.0, Q1 2014):

Wenn wir einen Remote-Tracking-Zweig mit dem Namen " frotz/nitfol" aus einem vorherigen Abruf haben und der Upstream jetzt einen Zweig mit dem Namen "** frotz " ** hat, kann fetch" frotz/nitfol" mit einem " git fetch --prune" nicht aus dem Upstream entfernt werden.
git würde den Benutzer informieren, " git remote prune" zu verwenden, um das Problem zu beheben.

Also: wenn eine Upstream - Repo hat einen Zweig ( „frotz“) mit dem gleichen Namen wie eine Zweig Hierarchie ( „frotz / xxx“, eine mögliche Zweignamenskonvention ), git remote --prunewurde Nachfolger (in der Reinigung die Fernortungs Niederlassung von Ihrem Repo - up) , git fetch --prunescheiterte aber.

Nicht länger:

Ändern Sie die Funktionsweise von " fetch --prune", indem Sie den Bereinigungsvorgang vor dem Abrufvorgang verschieben.
Auf diese Weise wird der Benutzer nicht vor einem Konflikt gewarnt, sondern automatisch behoben.

VonC
quelle