Entfernen Sie Tracking-Zweige nicht mehr auf der Fernbedienung


1172

Gibt es eine einfache Möglichkeit, alle Tracking-Zweige zu löschen, deren Remote-Äquivalent nicht mehr vorhanden ist?

Beispiel:

Niederlassungen (lokal und remote)

  • Meister
  • Herkunft / Meister
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

Vor Ort habe ich nur eine Hauptniederlassung. Jetzt muss ich an Bug-Fix-A arbeiten , also überprüfe ich es, arbeite daran und übertrage Änderungen auf die Fernbedienung. Als nächstes mache ich dasselbe mit Bug-Fix-B .

Niederlassungen (lokal und remote)

  • Meister
  • Bug-Fix-a
  • Bug-Fix-b
  • Herkunft / Meister
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

Jetzt habe ich lokale Zweigstellen Master , Bug-Fix-A , Bug-Fix-B . Der Master - Zweig Maintainer wird meine Änderungen in fusionieren Master und löschen Sie alle Zweige er bereits zusammengeführt hat.

Der aktuelle Status ist also jetzt:

Niederlassungen (lokal und remote)

  • Meister
  • Bug-Fix-a
  • Bug-Fix-b
  • Herkunft / Meister
  • origin / bug-fix-c

Jetzt möchte ich einen Befehl zum Löschen von Zweigen (in diesem Fall Bug-Fix-A , Bug-Fix-B ) aufrufen , die nicht mehr im Remote-Repository vertreten sind.

Es wäre so etwas wie der vorhandene Befehl git remote prune origin, aber eher so git local prune origin.

Antworten:


1282

git remote prune origin Pflaumen verfolgen Zweige nicht auf der Fernbedienung.

git branch --merged listet Zweige auf, die mit dem aktuellen Zweig zusammengeführt wurden.

xargs git branch -d löscht Zweige, die in der Standardeingabe aufgeführt sind.

Achten Sie darauf, die von aufgelisteten Zweige zu löschen git branch --merged. Die Liste kann masteroder andere Zweige enthalten, die Sie lieber nicht löschen möchten.

Um sich die Möglichkeit zu geben, die Liste vor dem Löschen von Zweigen zu bearbeiten, können Sie in einer Zeile Folgendes tun:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

17
Die erste Zeile der zusammengeführten Zweige befindet sich * masterauf meinem System. Der folgende Befehl hat bei mir funktioniert:git branch -d $(git branch --merged |tail -n +2)
Trendfischer

99
Wenn ich auf bin developdann git branch --mergedschließt master! Sie möchten das wahrscheinlich (definitiv!) Nicht löschen. Ich denke auch, dass es dort sein sollte, git branch -dwo Kleinbuchstaben -d"sicheres Löschen" bedeuten, z. B. nur löschen, wenn zusammengeführt.
thom_nic

11
Es scheint, dass dort eine verbesserte Lösung bereitgestellt wird .
Sergey Brunov

34
Zusammengeführt entfernt ist nützlich, aber nicht dasselbe wie "Zweige entfernen, die nicht auf der Fernbedienung sind".
dlsso

11
Verwenden Sie einfach grep, um master auszuschließen:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
geniass

590

Nach dem Befehl

git fetch -p

Entfernt die Remote-Referenzen, wenn Sie ausgeführt werden

git branch -vv

Als Remote-Status wird "weg" angezeigt. Zum Beispiel,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

So können Sie ein einfaches Skript schreiben, um lokale Zweige zu entfernen, die entfernt wurden:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

Beachten Sie, dass oben der Befehl "Porzellan" verwendet wird git branch, um den Upstream-Status abzurufen.

Eine andere Möglichkeit, diesen Status zu erhalten, besteht darin, den Befehl "plumbing" git for-each-refmit der Interpolationsvariablen zu verwenden %(upstream:track), die [gone]genau wie oben beschrieben ist.

Dieser Ansatz ist etwas sicherer, da kein Risiko besteht, dass ein Teil der Festschreibungsnachricht versehentlich übereinstimmt.

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

8
@KrzysztofWende - nicht auf Solaris und einigen BSDs und einigen OS X :)
jww

4
Es sieht so aus, als würde dadurch auch jeder Zweig entfernt, der in der letzten Festschreibungsnachricht "verschwunden" ist.
dlsso

11
@dlsso Wenn die letzte Festschreibungsnachricht die Zeichenfolge ": weg]" enthält, wird sie ebenfalls entfernt. Sie können es auf Kosten der Einfachheit robuster machen, indem Sie ein zusätzliches awk / gawk verwenden, um die Festschreibungsnachricht zu entfernen. git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
Jason.rickman

2
Als Antwort auf meinen vorherigen Kommentar (Frage) hat der aktuelle Zweig * als erstes Feld. Wenn es sich auch in der Liste der "verschwundenen" Zweige befindet, wird $ 1 zugewiesen * und als Dateispezifikation interpretiert, bei der awk Datei- und Ordnernamen ausspuckt. Ich habe den grep-Ausdruck entfernt und awk die gesamte Filterung durchführen lassen : awk '/: gone]/{if ($1!="*") print $1}'. Dies funktioniert jetzt wie erwartet.
rhaben

5
@ahmedbhs Da der Befehl ein einfaches Anführungszeichen verwendet, müssen Sie ein doppeltes Anführungszeichen verwenden, um den gesamten Befehl zu umgeben. Außerdem benötigen Git-Aliase, die Shell-Befehle (wie dieser) sind, am Anfang! Dies funktioniert für mich:test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
jason.rickman

306

Die meisten dieser Antworten beantworten die ursprüngliche Frage nicht. Ich habe ein paar Mal gegraben und dies war die sauberste Lösung, die ich gefunden habe. Hier ist eine etwas gründlichere Version dieser Antwort:

  1. Überprüfen Sie Ihren Standardzweig. Meistensgit checkout master
  2. Lauf git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Erläuterung:

Funktioniert, indem Sie Ihre Tracking-Zweige beschneiden und dann die lokalen löschen, die anzeigen, dass sie "verschwunden" sind git branch -vv.

Anmerkungen:

Wenn Ihre Sprache auf etwas anderes als Englisch eingestellt ist, müssen Sie gonedas entsprechende Wort ändern . Nur lokale Zweige werden nicht berührt. Zweige, die auf der Fernbedienung gelöscht, aber nicht zusammengeführt wurden, zeigen eine Benachrichtigung an, werden jedoch auf lokaler Ebene nicht gelöscht. Wenn Sie diese ebenfalls löschen möchten, wechseln Sie -dzu -D.


2
für Französisch OS gegangen müssen von disparue geändert werden
Mohamed EL HABIB

4
sollte LANG = en_US vor git branch hinzufügen, um Englisch zu erzwingen: git fetch --prune && LANG = en_US git branch -vv | awk '/: weg] / {print $ 1}' | Xargs Git Branch -d
Mohamed EL HABIB

3
Ich würde git checkout master && ...am Anfang des Befehls hinzufügen .
Iarroyo

2
Dies ist gefährlich, wenn Sie sich in einem Zweig befinden, der gelöscht werden soll. In diesem Fall lautet die erste Spalte '*' und wird dann an xargs übergeben. Um dies zu verbessern, fügen Sie das Zeichen '*' hinzu, bevor Sie die Ausgabe an awk übergeben: sed -e 's / ^ * //'
meeee

6
Vorsichtig! Es gibt einen Randfall, der zum Löschen aller Ihrer lokalen Zweige führt: Wenn Sie sich derzeit in einem Zweig befinden, der auf der Fernbedienung gelöscht wurde, git branch -vvbeginnt die Ausgabe von mit einem Sternchen, der letztendlich zur Ausführung führt git branch -d *. Hier ist eine gepatchte Version, die Zeilen mit Sternchen ignoriert:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
kcm

210

Normalerweise würde ich eine Frage mit 16 Antworten nicht beantworten, aber alle anderen Antworten sind falsch und die richtige Antwort ist so einfach. Die Frage lautet: "Gibt es eine einfache Möglichkeit, alle Tracking-Zweige zu löschen, deren Remote-Äquivalent nicht mehr vorhanden ist?"

Wenn "einfach" bedeutet, alle auf einmal zu löschen, nicht zerbrechlich, nicht gefährlich und ohne Vertrauen auf Tools, die nicht alle Leser haben, lautet die richtige Antwort: Nein.

Einige Antworten sind einfach, aber sie tun nicht das, was gefragt wurde. Andere tun, was gefragt wurde, sind aber nicht einfach: Alle verlassen sich darauf, die Git-Ausgabe über Textmanipulationsbefehle oder Skriptsprachen zu analysieren, die möglicherweise nicht auf jedem System vorhanden sind. Darüber hinaus verwenden die meisten Vorschläge Porzellanbefehle, deren Ausgabe nicht für die Analyse durch Skripte vorgesehen ist ("Porzellan" bezieht sich auf Befehle, die für den menschlichen Betrieb bestimmt sind; Skripte sollten die untergeordneten Befehle "Sanitär" verwenden).

Weiterführende Literatur:


Wenn Sie dies sicher tun möchten, müssen Sie für den Anwendungsfall in der Frage (Garbage-Collect-Tracking-Zweige, die auf dem Server gelöscht wurden, aber noch als lokale Zweige vorhanden sind) und nur Git-Befehle auf hoher Ebene verwenden

  • git fetch --prune(oder git fetch -p, was ein Alias ​​ist oder git prune remote originwas dasselbe tut, ohne es abzurufen, und wahrscheinlich nicht das ist, was Sie die meiste Zeit wollen).
  • Beachten Sie alle Remote-Zweige, die als gelöscht gemeldet werden. Oder, um sie später zu finden git branch -v(jeder verwaiste Verfolgungszweig wird mit "[weg]" markiert).
  • git branch -d [branch_name] auf jedem verwaisten Tracking-Zweig

(was einige der anderen Antworten vorschlagen).

Wenn Sie eine Lösung skripten möchten, for-each-refist dies Ihr Ausgangspunkt, wie in Mark Longairs Antwort hier und dieser Antwort auf eine andere Frage , aber ich sehe keine Möglichkeit, sie auszunutzen, ohne eine Shell-Skriptschleife zu schreiben oder xargs oder ähnliches zu verwenden .


Hintergrunderklärung

Um zu verstehen, was passiert, müssen Sie wissen, dass Sie in der Situation der Nachverfolgung von Zweigen nicht einen Zweig haben, sondern drei. (Und denken Sie daran, dass "Verzweigung" einfach einen Zeiger auf ein Commit bedeutet.)

Bei einem Tracking-Zweig feature/Xverfügt das Remote-Repository (Server) über diesen Zweig und ruft ihn auf feature/X. Ihr lokales Repository verfügt über einen Zweig, remotes/origin/feature/Xder bedeutet: "Dies hat mir die Fernbedienung mitgeteilt, dass der Feature- / X-Zweig das letzte Mal war, als wir gesprochen haben". Schließlich verfügt das lokale Repository über einen Zweig, feature/Xder auf Ihr letztes Commit verweist und für den konfiguriert ist "Spur" remotes/origin/feature/X, was bedeutet, dass Sie ziehen und drücken können, um sie ausgerichtet zu halten.

Irgendwann hat jemand das feature/Xauf der Fernbedienung gelöscht . Von diesem Moment an bleiben Sie bei Ihrem lokalen feature/X(was Sie wahrscheinlich nicht mehr wollen, da die Arbeit an Feature X vermutlich abgeschlossen ist) und Ihrem, remotes/origin/feature/Xwas sicherlich nutzlos ist, weil sein einziger Zweck darin bestand, sich den Status des Serverzweigs zu merken .

Und Git lässt Sie die Redundanz automatisch bereinigen remotes/origin/feature/X- das ist es, was es git fetch --prunetut - aber aus irgendeinem Grund können Sie Ihre eigenen nicht automatisch löschen feature/X... obwohl Ihre feature/Xnoch die verwaisten Tracking-Informationen enthält, so dass sie die Informationen enthalten um frühere Tracking-Zweige zu identifizieren, die vollständig zusammengeführt wurden. (Schließlich können Sie die Informationen erhalten, mit denen Sie die Operation von Hand selbst durchführen können.)


3
Dies ist eine viel sicherere Antwort. Darüber hinaus funktioniert es, wenn Sie im Gegensatz zur ausgewählten Antwort einen Workflow "Squash and Merge" verwenden.
Jake Levitt

3
Dies beantwortet wirklich nur den einfachen Teil der Frage "wie man verschwundene Zweige findet" (und zwar mit demselben Befehl, wie er bereits 2015 von jason.rickman veröffentlicht wurde), fordert Sie dann jedoch auf, alle Zweige manuell zu löschen, was genau das ist, was das OP tut will nicht tun.
Voo

4
@Voo Das ist der Punkt der Antwort: Ihnen nicht zu sagen, wie es geht (das ist nur ein Bonus), sondern Ihnen zu sagen, dass die Antwort lautet, dass es keinen einfachen Weg gibt, dies zu tun. Welches ist die richtige Antwort auf die Frage, wie sie formuliert wurde.
Andrew Spencer

1
"Wenn Sie dies sicher tun möchten, für den Anwendungsfall in der Frage .." - was die meisten Behauptungen des ersten Absatzes negiert. "[Git] kann Ihnen die Informationen geben, mit denen Sie die Operation von Hand selbst ausführen können" - wir sind Programmierer, daher ist die Aufgabe angesichts der Informationen als Liste (die angezeigt wird) immer noch einfach (z. B. xargs). Es gibt auch git aliaseine Reihe von Fällen zu vereinfachen.
user2864740

2
@ user2864740 Einige Leser mögen der Meinung sein, dass das Schreiben eines kleinen Bash-Skripts unter ihre Definition von "einfach" fällt, und das ist eine durchaus vertretbare Position, aber ich habe im 2. Absatz meine eigene Interpretation von "einfach" gegeben, und der Rest der Antwort ist konsistent damit. Und zur Verteidigung meiner zugegebenermaßen restriktiven Interpretation haben xargsoder schlagen nicht alle Git-Benutzer , und sie sind wahrscheinlich nicht hier, um nach einer Herausforderung für die Mikrocodierung zu suchen, sondern um eine schnelle Antwort, die sie sicher anwenden können, ohne sich weiter von ihrem eigentlichen Ziel abzulenken .
Andrew Spencer

52

Ich habe hier die Antwort gefunden: Wie kann ich alle zusammengeführten Git-Zweige löschen?

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d

Stellen Sie sicher, dass wir den Meister behalten

Sie können sicherstellen, dass masteroder ein anderer Zweig nicht entfernt wird, indem Sie grepnach dem ersten einen weiteren hinzufügen . In diesem Fall würden Sie gehen:

git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d

Also , wenn wir wollten , halten master, developund stagingzum Beispiel, würden wir gehen:

git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d

Machen Sie dies zu einem Alias

Da es etwas lang ist, möchten Sie möglicherweise einen Alias ​​zu Ihrem .zshrcoder hinzufügen .bashrc. Meins heißt gbpurge(für git branches purge):

alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'

Laden Sie dann Ihr .bashrcoder neu .zshrc:

. ~/.bashrc

oder

. ~/.zshrc

8
Nützlich, aber nicht dasselbe wie "Zweige nicht auf Remote entfernen"
dlsso

Greate answer @karlingen, ich habe dies permanent als gbpurge in all meinen Entwicklungsumgebungen
Peter Dolan

50

Windows-Lösung

Für Microsoft Windows Powershell:

git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}

Erklärung

git checkout master wechselt in den Hauptzweig

git remote update origin --prune beschneidet entfernte Zweige

git branch -vverhält eine ausführliche Ausgabe aller Zweige ( Git-Referenz )

Select-String -Pattern ": gone]" Ruft nur die Datensätze ab, bei denen sie von der Fernbedienung entfernt wurden.

% { $_.toString().Trim().Split(" ")[0]} Holen Sie sich den Filialnamen

% {git branch -d $_} löscht den Zweig


3
Vielen Dank für diese, obwohl ich hatte einen hinzufügen .Trim()nach , .toString()um vor dem Zweignamen zu entfernen , zwei Räume.
Matthew

2
Danke für diesen Befehl. Ich musste das ändern git branch -d, git branch -Dsonst bekomme ich den Fehler, dass der Zweig nicht vollständig zusammengeführt ist.
Markieo

1
@markieo Du weißt das wahrscheinlich schon, aber für alle anderen - git branch -Dist destruktiv und löscht lokale Arbeiten, die du noch nicht gepusht hast. -dist immer sicher, sei einfach vorsichtig mit -D.
Nate Barbettini

33

Der Mustervergleich für "weg" in den meisten anderen Lösungen war für mich ein wenig beängstigend. Um sicherer zu sein, wird das --formatFlag verwendet, um den Upstream-Tracking-Status jedes Zweigs abzurufen .

Ich brauchte eine Windows-freundliche Version, damit alle Zweige, die mit Powershell als "weg" aufgeführt sind, gelöscht werden:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

In der ersten Zeile wird der Name der lokalen Zweige aufgeführt, deren vorgelagerter Zweig "weg" ist. In der nächsten Zeile werden leere Zeilen entfernt (die für Zweige ausgegeben werden, die nicht "weg" sind). Anschließend wird der Zweigname an den Befehl zum Löschen des Zweigs übergeben.


6
Die --formatOption scheint ziemlich neu zu sein; Ich musste git von 2.10.something auf 2.16.3 aktualisieren, um es zu bekommen. Dies ist meine Modifikation für Linux-ish Systeme:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D
BXM

2
Dies ist die bisher beste Lösung. Ein Vorschlag ist zu verwenden refname:short. Dann können Sie die Zeile löschen% { $_ -replace '^refs/heads/', '' }
ioudas

2
Dies ist eine großartige Lösung für Windows. Ich bin es , wie diese Sache verwendet , ist es besser lesbar git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }auch wahrscheinlich eine gute Idee zu verwenden , -dstatt -D. Das Löschen erzwingen sollte nicht für Zweige erforderlich sein, die sich nicht mehr auf der Fernbedienung befinden.
Rubanov

31

Entfernen Sie alle Zweige, die zum Master zusammengeführt wurden, aber versuchen Sie nicht, den Master selbst zu entfernen:

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

oder fügen Sie einen Alias ​​hinzu:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

Erläuterung:

git checkout master Checkout-Hauptzweig

git pull origin master Stellen Sie sicher, dass in der lokalen Niederlassung alle Remote-Änderungen zusammengeführt wurden

git fetch -p Entfernen Sie Verweise auf gelöschte Remote-Zweige

git branch -d $(git branch master --merged | grep master -v) Löschen Sie alle Zweige, die zum Master zusammengeführt wurden, aber versuchen Sie nicht, den Master selbst zu entfernen


3
Ein Hinweis, dies ist sehr hilfreich, entfernt aber auch die Zweige, die noch nie auf die Fernbedienung übertragen wurden. Es ist sicherer, nur Unterschiede git branch -D
aufzulisten

Zur Verdeutlichung bezieht sich Zefiryn auf die Verwendung der Option -D, die nicht Teil des Einzeilers ist.
CS01

1
Oder verwenden Sie Kleinbuchstaben, git branch -ddie eine Warnung vor nicht geschobenen Zweigen ausgeben sollten.
Acme

16
git fetch -p

Dies wird beschneidet alle Zweige , dass nicht mehr existiert auf der Fernbedienung.


64
Dadurch werden Remote-Referenzen entfernt, nicht jedoch die lokalen Zweige. Obwohl dies ein nützlicher Befehl ist, glaube ich nicht, dass dies die Frage von OP beantwortet.
Thataustin

Was? Dadurch werden lokale Zweige für mich gelöscht.
Alex Hall

1
@AlexHall Das Remote-Repository hat einen Zweig X. du git checkout X; Jetzt verfügt Ihr Repository über einen (lokalen) Tracking-Zweig Xund einen Remote-Zweig origin/X. Das Remote-Repository wird gelöscht X. du git fetch-p; in Ihrem lokalen Repository wurden nicht nur, origin/Xsondern auch Xgelöscht. Sagst du das?
Andrew Spencer

16

Noch eine weitere Antwort für den Stapel, die sich stark auf Patricks Antwort stützt (was mir gefällt, weil sie jegliche Unklarheit darüber zu beseitigen scheint, wo gone]in der git branchAusgabe übereinstimmen wird), aber eine * nix-Biegung hinzufügt.

In seiner einfachsten Form:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

Ich habe dies in ein git-goneSkript auf meinem Weg eingepackt :

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB - Die --formatOption scheint ziemlich neu zu sein. Ich musste git von 2.10.something auf 2.16.3 aktualisieren, um es zu bekommen.

EDIT: optimiert, um Vorschläge refname:shortvon Benjamin W. aufzunehmen.

NB2 - Ich habe nur in getestet bash, daher der Hashbang, aber wahrscheinlich portabel zu sh.


Können Sie das sedTeil nicht überspringen, indem Sie es %(refname:short)in der ersten Zeile verwenden?
Benjamin W.

Scheint für mich zu funktionieren und ich habe es jetzt als ordentlichen Git-Alias ​​- die sauberste Lösung von allen hier!
Benjamin W.

2.13 eingeführt --format. Eine andere Möglichkeit, das sedTeil zu überspringen, ist die Verwendung git update-ref -d. Beachten Sie, dass dies wahrscheinlich etwas unsicher ist. Die Verwendung git for-each-refist hier sicherer (angegeben --shell).
Gsnedders

Tolle Antwort, und es hat mir geholfen, meine eigenen Fragen zu beantworten, wenn --formatich damit zapple , dies selbst zu tun. Nur eine Frage: Warum die #!bash? Alles hier sieht shfür mich wie tragbar aus .
Toby Speight

Das ist nur meine normale Heizplatte und wurde nicht anderswo getestet.
bxm

15

Könnte für einige einfache Zeilen nützlich sein, um alle lokalen Zweige außer Master und Entwicklung zu löschen

git branch | grep -v "master" | grep -v "develop" | xargs git branch -D

Super Antwort! Mir gefällt, wie man leicht mit 'git branch | grep -v "master" | grep -v "develop"solchen Dingen spielen kann, bevor man sich dazu verpflichtet, den Löschteil des Befehls hinzuzufügen. 👏😊
finneycanhelp

Dies beantwortet jedoch nicht die obige Frage. Dadurch werden Zweige gelöscht, obwohl die Fernbedienung noch vorhanden ist.
Jim.B

13

Dadurch werden alle zusammengeführten lokalen Verzweigungen mit Ausnahme der lokalen Hauptreferenz und der aktuell verwendeten gelöscht:

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

Dadurch werden alle Zweige gelöscht, die bereits aus dem Remote-Repository entfernt wurden, auf das durch " origin " , die jedoch lokal in " remotes / origin " verfügbar sind .

git remote prune origin

git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d Erläuterung: Ich ziehe es vor, das git branch --mergeddurch git branch -vvzu ersetzen , um den Status git branch --merged
anzuzeigen

13

Ich glaube nicht, dass es einen eingebauten Befehl gibt, um dies zu tun, aber es ist sicher, Folgendes zu tun:

git checkout master
git branch -d bug-fix-a

Wenn Sie verwenden -d, weigert sich git, den Zweig zu löschen, es sei denn, er wird vollständig in den Zweig HEADoder den vorgelagerten Fernverfolgungszweig zusammengeführt. Sie können also jederzeit die Ausgabe von git for-each-refdurchlaufen und versuchen, jeden Zweig zu löschen. Das Problem bei diesem Ansatz ist, dass ich vermute, dass Sie wahrscheinlich nicht bug-fix-dgelöscht werden möchten , nur weil es origin/bug-fix-dseinen Verlauf enthält. Stattdessen können Sie ein Skript wie das folgende erstellen:

#!/bin/sh

git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
  if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
  then
    if [ "$r" != "master" ]
    then
      git branch -d "$r"
    fi
  fi
done

Warnung: Ich habe dieses Skript nicht getestet - nur mit Vorsicht verwenden ...


Ich habe mir erlaubt, das Skript zu bearbeiten. Ich werde immer noch keine Garantien geben, aber es läuft und scheint jetzt zu funktionieren.
Fwielstra

13

TL; DR:

Entfernen Sie ALLE lokalen Zweige, die sich nicht auf der Fernbedienung befinden

git fetch -p && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D

Entfernen Sie ALLE lokalen Zweige, die sich nicht auf Remote befinden UND die vollständig zusammengeführt sind UND die nicht wie in vielen Antworten zuvor verwendet verwendet wurden.

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

Erläuterung

  • git fetch -p beschneidet alle Zweige, die auf der Fernbedienung nicht mehr vorhanden sind
  • git branch -vv druckt lokale Zweige und beschnittene Zweige werden mit markiert gone
  • grep ': gone]' Wählt nur den Zweig aus, der weg ist
  • awk '{print $1}' Filtern Sie die Ausgabe, um nur den Namen der Zweige anzuzeigen
  • xargs git branch -D wird alle Linien (Zweige) durchlaufen und diesen Zweig zwangsweise entfernen

Warum git branch -Dund nicht git branch -dsonst haben Sie für Zweige, die nicht vollständig zusammengeführt sind.

error: The branch 'xxx' is not fully merged.

1
Wolltest du Remote statt Master sagen?
Tinos

8

Sie könnten dies tun:

git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d

7

Basierend auf den obigen Informationen hat dies bei mir funktioniert:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

Es werden alle lokalen Zweige entfernt, die sich ': gone] 'auf der Fernbedienung befinden.


1
Es sieht so aus, als würde dadurch auch jeder Zweig entfernt, der in der letzten Festschreibungsnachricht "verschwunden" ist.
dlsso

Außerdem werden alle Zweige entfernt, gonederen Name eine beliebige Stelle enthält.
Bfontaine

3
"git branch -D git branch -vv | grep ': weg]' | awk '{print $ 1}' | xargs`" Das hat die Arbeit für mich erledigt.
Muthu Ganapathy Nathan

7
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

Mit dem obigen Befehl können Zweige abgerufen werden, die in Remote zusammengeführt und gelöscht werden, und der lokale Zweig wird gelöscht, der in Remote nicht mehr verfügbar ist


Beste Lösung bisher, obwohl ich es geändert habe, grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -Dum das Löschen aller zu erzwingen
Shoaib

Gefährlich, wenn einer Ihrer Zweignamen die Teilzeichenfolge goneirgendwo in ihnen enthält (z usingonefunction. B. ).
Toby Speight

7

Nichts davon war wirklich richtig für mich. Ich wollte etwas, das alle lokalen Zweige löscht, die einen Remote-Zweig verfolgen, auf origindem der Remote-Zweig gelöscht wurde ( gone). Ich wollte keine lokalen Zweige löschen, die nie für die Verfolgung eines Remote-Zweigs eingerichtet wurden (dh meine lokalen Entwicklungszweige). Außerdem wollte ich einen einfachen Einzeiler, der nur verwendet git, oder andere einfache CLI-Tools, anstatt benutzerdefinierte Skripte zu schreiben. Am Ende habe ich ein bisschen von grepund verwendetawk , um diesen einfachen Befehl zu machen.

Dies ist letztendlich das, was in meinem endete ~/.gitconfig:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D

Hier ist ein git config --global ...Befehl zum einfachen Hinzufügen 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'

HINWEIS: Im Befehl config verwende ich die -dOption git branchanstatt -Dwie in meiner eigentlichen Konfiguration. Ich benutze, -Dweil ich nicht will, dass Git sich über nicht zusammengeführte Zweige beschwert. Möglicherweise möchten Sie diese Funktionalität auch. Wenn ja, verwenden Sie einfach -Dstatt -dam Ende dieses Konfigurationsbefehls.


Ich mag den Git-Alias-Ansatz. git branch -vvKurze Frage: Warum tun und greifen : gone]und nicht tun git branch -vund greifen [gone]?
Lalibi

@lalibi, gute Frage. Ich erinnere mich nicht. Ich vermute, dass etwas nicht mit nur einem auftauchte v. Wenn es git branch -v | grep '[gone]'für Sie funktioniert, machen Sie es. Es scheint ein bisschen sauberer.
Karl Wilbur

4

Basierend auf Git Tipp: Löschen alter lokaler Zweige , der der Lösung von jason.rickman ähnelt. Zu diesem Zweck habe ich einen benutzerdefinierten Befehl namens git gegangen, der mit Bash weg ist :

$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
  -p  prune remote branch
  -n  dry run: list the gone branches
  -d  delete the gone branches
  -D  delete the gone branches forcefully

EXAMPLES
git gone -pn    prune and dry run
git gone -d     delete the gone branches

git gone -pn kombiniert das Beschneiden und Auflisten der "verschwundenen" Zweige:

$ git gone -pn
  bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
  fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules

Dann können Sie mit git gone -doder den Abzug betätigengit gone -D .

Anmerkungen

  • Der reguläre Ausdruck, den ich verwendet habe, ist, "$BRANCH/.*: gone]"wo $BRANCHnormalerweiseorigin . Dies wird wahrscheinlich nicht funktionieren, wenn Ihre Git-Ausgabe auf Französisch usw. lokalisiert ist.
  • Sebastian Wiesner portierte es auch auf Rust für Windows-Benutzer. Dieser wird auch git weg genannt .

Dies sollte wahrscheinlich die akzeptierte Antwort sein - git gonesieht aus wie ein Alias ​​für git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d, der das Problem des OP löst.
Alex

4

Zeichnung stark von einer Reihe von anderen Antworten hier, ich habe mit dem folgenden (nur git 2.13 und höher, glaube ich) endete, die auf jedem UNIX-ähnliche Shell funktionieren sollen:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

Dies verwendet insbesondere for-each-refanstelle von branch(wie branches ein "Porzellan" -Befehl ist, der für eine vom Menschen lesbare Ausgabe und nicht für eine maschinelle Verarbeitung entwickelt wurde) und verwendet sein --shellArgument, um eine ordnungsgemäß maskierte Ausgabe zu erhalten (dies ermöglicht es uns, uns keine Gedanken über ein Zeichen im Referenznamen zu machen).


Es funktioniert für mich, aber es wäre auch schön, wenn Sie erklären könnten, was die anderen Schritte im Befehl tun. Zum Beispiel weiß ich nicht was [ ! -z "$ref" ]bedeutet. Ich denke, ein Multi-Liner hätte schon geholfen. Trotzdem danke für deine Eingabe!
KevinH

4

Noch eine Antwort, denn keine der Lösungen entspricht meinen Anforderungen an Eleganz und Plattformübergreifend:

Befehl zum Löschen lokaler Zweige, die sich nicht auf der Fernbedienung befinden:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

So integrieren Sie es in gitconfig, damit es ausgeführt werden kann mit git branch-prune:

Bash

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

Power Shell

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(Benötigen Sie Hilfe bei der Suche nach einem universellen Befehl für PowerShell und Bash)

Warum ist diese Antwort die beste?

  • Bietet eine Komplettlösung: Fügt git branch-pruneIhrem Git einen Befehl hinzu
  • Funktioniert gut mit Windows PowerShell
  • Die Kernidee ist @ jason.rickman ‚s kugelsicher Methode unter Verwendung vongit for-each-ref
  • Das Parsen und Filtern erfolgt --filterohne externe Abhängigkeiten

Erläuterung:

  • Fügt Ihrem einen neuen Alias ​​hinzu ~\.gitconfig. Nachdem Sie dies ausgeführt haben, können Sie es einfach tungit branch-prune
  • In diesem Alias:
    • Ruft Zweige mit der --pruneFlagge ab, die "Fernverfolgungszweige nicht mehr auf der Fernbedienung beschneidet".
    • Verwendet git for-each-refund --filter, um eine Liste der Zweige zu erhalten, sind [gone](keine Fernbedienung)
    • Durchläuft diese Liste und löscht den Zweig sicher

1
Vielen Dank, @ jerry-wu, für die Verbesserung der Attraktivität dieser Lösung bis ins Unendliche.
Himura

@ jerry-wu und Ihre letzte Bearbeitung des Befehls git config funktioniert in PowerShell nicht ((
Himura,

1

Ich habe mir dieses Bash-Skript ausgedacht. Es bleibt immer die Zweige develop, qa, master.

git-clear() {
  git pull -a > /dev/null

  local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
  branches=(${branches//;/ })

  if [ -z $branches ]; then
    echo 'No branches to delete...'
    return;
  fi

  echo $branches

  echo 'Do you want to delete these merged branches? (y/n)'
  read yn
  case $yn in
      [^Yy]* ) return;;
  esac

  echo 'Deleting...'

  git remote prune origin
  echo $branches | xargs git branch -d
  git branch -vv
}

1

Ich verwende eine kurze Methode, um den Trick auszuführen. Ich empfehle Ihnen, dasselbe zu tun, da dies einige Stunden sparen und Ihnen mehr Sichtbarkeit geben könnte

Fügen Sie einfach das folgende Snippet zu Ihrem .bashrc hinzu (.bashprofile on macos).

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. Holen Sie sich alle Fernbedienungen
  2. Holen Sie sich nur zusammengeführte Zweige von git
  3. Entfernen Sie aus dieser Liste die "geschützten / wichtigen" Zweige
  4. Entfernen Sie den Rest (z. B. saubere und zusammengeführte Zweige).

Sie müssen den Grep-Regex bearbeiten, um ihn Ihren Anforderungen anzupassen (hier wird verhindert, dass Master, Preprod und DMZ gelöscht werden).


git fetch --all --prunehat den Trick gemacht. Vielen Dank!
LeOn - Han Li

1

Das hat bei mir funktioniert:

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d

Oh, ich habe das doppelt gepostet auf ... habe es gerade beim Überprüfen von Posts gesehen. Aber Sie könnten wirklich auf den Mann zeigen, der diesen Befehl gegeben hat, anstatt ihn als Ihren zu betrachten!
Dwza

Ich bekomme es von einem Forum, versuche nicht schlau zu sein, nimm einfach die Antwort oder ignoriere sie
Fareed Alnamrouti

Auch als Sie ... sowieso ... nicht hierher gekommen sind, um dies mit Ihnen zu besprechen. Wie du gesagt hast ... nimm meinen Kommentar oder ignoriere ihn;)
Dwza

0

Ich bin mir nicht sicher, wie lange, aber ich benutze jetzt Git-Up, das sich darum kümmert.

Ich tue es git upund es beginnt, neue Zweige zu verfolgen und die alten zu löschen.

Nur um es klar zu machen, es ist kein sofort einsatzbereiter git-Befehl - https://github.com/aanand/git-up

Übrigens verstaut es auch schmutzigen Baum und macht Rebases immer noch mit nur git up.

Hoffe, es wird für jemanden nützlich sein


2
Dadurch werden keine lokalen Zweige gelöscht, die nicht auf dem Server vorhanden sind.
Ashley

0

Hier ist eine Lösung, die ich für die Fischschale verwende. Getestet auf Mac OS X 10.11.5, fish 2.3.0und git 2.8.3.

function git_clean_branches
  set base_branch develop

  # work from our base branch
  git checkout $base_branch

  # remove local tracking branches where the remote branch is gone
  git fetch -p

  # find all local branches that have been merged into the base branch
  # and delete any without a corresponding remote branch
  set local
  for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
    set local $local $f
  end

  set remote
  for f in (git branch -r | xargs basename)
    set remote $remote $f
  end

  for f in $local
    echo $remote | grep --quiet "\s$f\s"
    if [ $status -gt 0 ]
      git branch -d $f
    end
  end
end

Ein paar Anmerkungen:

Stellen Sie sicher, dass Sie die richtige Einstellung vornehmen base_branch. In diesem Fall verwende ich developals Basiszweig, aber es könnte alles sein.

Dieser Teil ist sehr wichtig: grep -v "\(master\|$base_branch\|\*\)" . Es stellt sicher, dass Sie weder den Master noch Ihren Basiszweig löschen.

Ich verwende dies git branch -d <branch>als zusätzliche Vorsichtsmaßnahme, um keinen Zweig zu löschen, der nicht vollständig mit dem vorgelagerten oder aktuellen HEAD zusammengeführt wurde.

Eine einfache Möglichkeit zum Testen ist das Ersetzen git branch -d $fdurch echo "will delete $f".

Ich sollte wohl auch hinzufügen: VERWENDUNG AUF EIGENES RISIKO!


0

Ich habe ein Python-Skript mit GitPython geschrieben , um lokale Zweige zu löschen, die auf Remote nicht vorhanden sind.

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)

        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)

        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])


        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

Hoffe, jemand findet es nützlich, bitte fügen Sie Kommentare hinzu, wenn ich etwas verpasst habe.


0

Wenn Sie zshShell mit verwendenOh My Zsh installierter Funktion verwenden, können Sie dies am einfachsten sicher tun, die integrierte automatische Vervollständigung verwenden.

Bestimmen Sie zunächst, mit welchen Zweigen Sie löschen möchten:

~ git branch --merged

  branch1
  branch2
  branch3
* master

Dies zeigt Ihnen eine Liste bereits zusammengeführter Zweige

Nachdem Sie einige kennen, die Sie löschen möchten, geben Sie Folgendes ein:

~ git branch -d 

Alles was Sie tun müssen, ist [Tab] zu drücken und es wird eine Liste der lokalen Niederlassungen angezeigt. Verwenden Sie die Tabulatortaste oder drücken Sie erneut die Tabulatortaste, und Sie können sie durchlaufen, um einen Zweig mit der Eingabetaste auszuwählen.

Registerkarte Wählen Sie die Zweige immer wieder aus, bis Sie eine Liste der Zweige haben, die Sie löschen möchten:

~ git branch -d branch1 branch2 branch3

Drücken Sie jetzt einfach die Eingabetaste, um Ihre Sammlung von Zweigen zu löschen.

Wenn Sie zsh nicht auf Ihrem Terminal verwenden ... Holen Sie es sich hier.


0

Ich benutze gerne Pipes, weil es den Befehl leichter lesbar macht.

Dies ist meine Lösung, wenn Sie alle Zweige außer Master entfernen möchten.

git branch | grep -v master | xargs -n 1 git branch -D

Ändern Sie den ersten und zweiten Block, um andere Zweige zu löschen, die Ihren Kriterien entsprechen.

git branch --merged | grep feature_name | xargs -n 1 git branch -D

-3

Hier ist die einfache Antwort, die für mich mit einem Git-Client funktioniert hat:

Löschen Sie das Repository vollständig von Ihrem Computer und checken Sie es erneut aus.

Kein Herumspielen mit riskanten Skripten.


2
Was ist mit den Filialen, an denen ich gerade arbeite: /
Mailo Světel

@ MailoSvětel Wenn sie sich auf Ihrer Fernbedienung befinden, können Sie sie einfach erneut ziehen (denken Sie daran, Ihre neuesten Arbeiten festzuschreiben und auf Ihre Fernbedienung zu übertragen!)
Juan Carlos Ospina Gonzalez

In meiner Frage und in den meisten Antworten versuchen wir, unnötige Arbeit zu vermeiden. Mit anderen Worten: Ich muss nur die Zweige entfernen, ich werde nicht mehr daran arbeiten. Das Entfernen von Repo, das Klonen und das erneute Verfolgen der Zweige ist für mich eine Menge unnötiger Arbeit. Außerdem könnte etwas Arbeit verloren gehen :(
Mailo Světel
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.