Alte entfernte Git-Zweige aufräumen

694

Ich arbeite auf zwei verschiedenen Computern (A und B) und speichere eine gemeinsame Git-Fernbedienung im Dropbox-Verzeichnis.

Nehmen wir an, ich habe zwei Zweige, Master und Devel. Beide verfolgen den Ursprung / Master und den Ursprung / die Entwicklung ihrer entfernten Gegenstücke.

Jetzt lösche ich auf Computer A die Zweigentwicklung auf lokaler und entfernter Ebene.

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

Wenn git branch -aich auf Computer A laufe, erhalte ich die folgende Liste von Zweigen.

  • Meister
  • Herkunft / KOPF
  • Herkunft / Meister

Unter git fetchComputer B kann ich den lokalen Entwicklungszweig mit git branch -d develentfernen, aber den Remote-Entwicklungszweig nicht entfernen.

git push origin :heads/devel gibt die folgenden Fehlermeldungen zurück.

Fehler: Push an nicht qualifiziertes Ziel nicht möglich: Heads / Proxy3d
Die Zielreferenzspezifikation stimmt weder mit einer vorhandenen Referenz auf der Fernbedienung überein noch beginnt sie mit Referenz /, und wir können kein Präfix basierend auf der Quellreferenz erraten.
tödlich: Das entfernte Ende legte unerwartet auf

git branch -a listet weiterhin Ursprung / Entwicklung in den entfernten Zweigen auf.

Wie kann ich die Remote-Zweige von Computer B bereinigen?

Jayesh
quelle
4
Einer, der es ausprobiert hat, hat mir gesagt, dass Git-Repositorys in Dropbox-Ordnern etwas zerbrechlich sind (aber ohne zusätzliche Details).
Thorbjørn Ravn Andersen
5
@ ThorbjørnRavnAndersen wahrscheinlich, weil Sie warten müssen, um sicherzustellen, dass es bei jedem Commit vollständig synchronisiert wird, bevor Sie sicher sein können, dass es sicher auf dem anderen Computer verwendet werden kann (und eine weitere Synchronisierung auch dann erforderlich ist).
Ataulm

Antworten:

1239

Was ist das Ergebnis von git branch -aMaschine B?

Zweitens haben Sie bereits gelöscht heads/develauf origin, ist also, warum man es nicht von der Maschine B. löschen

Versuchen

git branch -r -d origin/devel

oder

git remote prune origin

oder

git fetch origin --prune

Sie können --dry-rundas Ende Ihrer gitAnweisung hinzufügen , um das Ergebnis der Ausführung zu sehen, ohne sie tatsächlich auszuführen.

Dokumente für git remote pruneund git branch.

Jakub Narębski
quelle
50
git remote prune originarbeitete für mich => * [pruned] origin/my-old-branch
Hari Karam Singh
126
git remote prune origin --dry-runzeigt Ihnen, was gelöscht würde, ohne es tatsächlich zu tun.
Wolfram Arnold
30
git fetch origin --prunewar perfekt, um gelöschte Zweige zu entfernen
Sébastien Barbieri
10
Wenn Sie eine lokale Niederlassung haben, die eine entfernte Fernbedienung verfolgt, wird dadurch nichts gelöscht. Für diese scheint es git branch -vvgefolgt zu sein git branch -D branchnameund schließlich ist die Pflaume der beste Weg.
Roman Starkov
7
Sie können das Bereinigen so konfigurieren, dass es beim Ziehen / Abrufen automatisch erfolgt, indem Sie die folgende Option einstellen:git config remote.origin.prune true
Patrick James McDougle
99

Überlegen Sie, ob Sie Folgendes ausführen möchten:

git fetch --prune

Regelmäßig in jedem Repo, um lokale Zweige zu entfernen, die einen gelöschten Remote-Zweig verfolgt haben (im Remote-GIT-Repo nicht mehr vorhanden).

Dies kann weiter vereinfacht werden durch

git config remote.origin.prune true

Dies ist eine per-repoEinstellung, mit der jede Zukunft git fetch or git pullautomatisch beschnitten werden kann .

Um dies für Ihren Benutzer einzurichten, können Sie auch die globale .gitconfig bearbeiten und hinzufügen

[fetch]
    prune = true

Es wird jedoch empfohlen, dies mit dem folgenden Befehl durchzuführen:

git config --global fetch.prune true

oder um es systemweit anzuwenden (nicht nur für den Benutzer)

git config --system fetch.prune true
Arif
quelle
14

Hier ist ein Bash-Skript, das dies für Sie erledigen kann. Es ist eine modifizierte Version des Skripts http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git . Durch meine Änderung können verschiedene Remote-Standorte unterstützt werden.

#!/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
Alex Amiryan
quelle
1
Dies brach auf einem Zweig namens "origin / feature / mybranch", ich bin mir nicht sicher warum.
Stavros Korokithakis
Problem ist in den beiden seds. Ersetzen sed 's/\(.*\)\/\(.*\)/\1/g'durchsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier
14

Dieser Befehl "trocken laufen" löscht alle remote ( origin) zusammengeführten Zweige außer master. Sie können dies ändern oder nach dem Master weitere Zweige hinzufügen: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

Wenn es gut aussieht, entfernen Sie die --dry-run. Darüber hinaus möchten Sie dies möglicherweise zuerst an einer Gabel testen.

Weston
quelle
Nett. Mein Tweak mit Perl anstelle des 1. xargs + awk: git branch -r --merged | grep origin | grep -v '>' | grep -v master | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | Xargs Git Push Ursprung
Andrew
6

Wenn git branch -rviele Remote-Tracking-Zweige angezeigt werden, an denen Sie nicht interessiert sind und die Sie nur aus dem lokalen Bereich entfernen möchten, verwenden Sie den folgenden Befehl:

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

Eine sicherere Version wäre, nur die zusammengeführten zu entfernen:

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

Dies kann für große Projekte nützlich sein, bei denen Sie nicht die Feature-Zweige anderer Teammitglieder benötigen, aber beim ersten Klon viele Remote-Tracking-Zweige abgerufen werden.

Dieser Schritt allein reicht jedoch nicht aus, da diese gelöschten Fernverfolgungszweige als nächstes wiederkommen würden git fetch.

Um das Abrufen dieser Remote-Tracking-Zweige zu beenden, müssen Sie die Refs, die in .git / config abgerufen werden sollen, explizit angeben :

[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/*

Im obigen Beispiel holen wir nur master, developund lassen Sie Zweige, fühlen Sie sich frei anpassen , wie Sie benötigen.

Ryenus
quelle
1
Danke, der erste Befehl hat bei mir funktioniert. Sie können auch nur einen Zweig mit abrufen git fetch origin branchnameoder einen Alias ​​erstellen ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f", um nur den aktuellen Zweig abzurufen (mein persönlicher Favorit). Prost.
GiovanyMoreno
Vielleicht OT, aber was bedeutet die -rFlagge? Ich sehe, xargshat ein -RArgument, aber nichts gefunden -r. Ich meine, theoretisch, wenn ich mich richtig erinnere, wie es xargsfunktioniert, sollte es auch ohne -rfunktionieren.
Aldo 'xoen' Giambelluca
Ich mag diese Antwort. Ein paar Notizen (die das Offensichtliche wirklich angeben). Sie können eine "Vorschau" anzeigen, welche Zweige gelöscht werden sollen, indem Sie die letzte Pipe und den letzten Befehl entfernen | xargs git branch -d. Durch Entfernen der -rOption ( --remotes) werden git branch -dnur die lokalen Zweige bereinigt (was möglicherweise ausreicht, wenn man bedenkt, dass standardmäßig git branchohnehin keine entfernten Zweige angezeigt werden).
Aldo 'xoen' Giambelluca
Vielen Dank! Das war genau das, was ich brauchte. Andere Lösungen schlagen vor, beschnittene lokale Zweige auf die Fernbedienung zu schieben, um sie dort ebenfalls zu entfernen. Dies hilft jedoch nicht, wenn die Fernbedienung entfernt wurde oder nicht mehr vorhanden ist. Dieser Ansatz entfernte die lokalen Verweise auf die Remote-Zweige, auf die ich keinen Zugriff mehr habe.
Vorsicht Bug
@aldo, über xargs -r, nämlich --no-run-if-empty, es ist eine GNU-Erweiterung bedeutet, hier ist eine schöne Erklärung .
Ryenus
4

Das Löschen ist immer eine herausfordernde Aufgabe und kann gefährlich sein !!! Führen Sie daher zuerst den folgenden Befehl aus, um zu sehen, was passieren wird:

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

Auf diese Weise erhalten gitSie eine Liste der Vorgänge, die bei Ausführung des folgenden Befehls ausgeführt werden.

Führen Sie dann den folgenden Befehl aus, um alle Zweige aus dem Remote-Repo zu entfernen, die sich nicht in Ihrem lokalen Repo befinden:

git push --all --prune
Timothy LJ Stewart
quelle
10
Dieser Befehl scheint gefährlich zu sein ... Er konnte löschen, was ich wollte (und konnte mit mindestens vier der obigen Antworten nicht umgehen). Es wurden aber auch vier weitere Entwicklerzweige gelöscht. Git ist absolut zum Kotzen ...
jww
2
Diese Filialen müssen sich nicht in Ihrer Nähe befunden haben. Es ist jedoch nicht alles verloren. Git Commit, Git Reflog und dann Git Reset --hard <checksum>. Sie können damit buchstäblich zu jedem Commit (auch bekannt als Speichern) und anderen. Branch ist nur ein Label. Durch das Löschen des Labels wird das Speichern nicht gelöscht. Es wird für immer eine Prüfsumme haben. Lassen Sie mich wissen, ob ich helfen kann
Timothy LJ Stewart
3
Natürlich sollten Sie diese ziemlich schnell wiederherstellen, da der Garbage Collector von git schließlich Commits entfernt, auf die nicht von Zweigen verwiesen wird.
Andrew
1
Es ist gut, -ndiesem Befehl (Trockenlauf) hinzuzufügen, damit Sie eine Vorschau der Änderungen anzeigen können. Wenn alles in Ordnung ist, rufen Sie ihn erneut ohne auf -n.
mati865
1
Einverstanden mit @GuiWeinmann - Dies ist zu gefährlich, insbesondere ohne ein bestimmtes Callout, um dies zumindest zuerst im Trockenlauf auszuführen.
Vivek M. Chawla
2

So geht's mit SourceTree (v2.3.1):
1. Klicken Sie auf Abrufen.
2. Aktivieren Sie "Prune Tracking-Zweige ...".
3.
Drücken Sie OK. 4. 😀

Geben Sie hier die Bildbeschreibung ein

Kokos
quelle
1

Ich muss hier eine Antwort hinzufügen, da die anderen Antworten entweder meinen Fall nicht abdecken oder unnötig kompliziert sind. Ich verwende Github mit anderen Entwicklern und möchte nur, dass alle lokalen Zweige, deren Fernbedienungen (möglicherweise zusammengeführt und) aus einem Github-PR gelöscht wurden, auf einmal von meinem Computer gelöscht werden. Nein, Dinge wie git branch -r --mergeddecken nicht die Zweige ab, die nicht lokal zusammengeführt wurden, oder diejenigen, die überhaupt nicht zusammengeführt wurden (aufgegeben) usw., daher ist eine andere Lösung erforderlich.

Wie auch immer, der erste Schritt, den ich aus anderen Antworten bekam:

git fetch --prune

Ein trockener Lauf von git remote prune originschien in meinem Fall dasselbe zu tun, also habe ich mich für die kürzeste Version entschieden, um es einfach zu halten.

Jetzt git branch -vsollte a die Zweige markieren, deren Fernbedienungen als gelöscht werden [gone]. Daher muss ich nur Folgendes tun:

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

So einfach ist das, es löscht alles, was ich für das obige Szenario will.

Die weniger verbreitete xargsSyntax ist, dass sie neben Linux auch auf Mac & BSD funktioniert. Vorsicht, dieser Befehl ist kein Trockenlauf, daher werden alle als gekennzeichneten Zweige erzwungen [gone]. Wenn Sie sehen, dass Zweige gelöscht wurden, an die Sie sich erinnern, dass Sie sie behalten möchten, können Sie sie jederzeit wiederherstellen (der obige Befehl hat ihren Hash beim Löschen aufgelistet, also einfach git checkout -b <branch> <hash>.

Ecuador
quelle
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

Beschneiden Sie die gleichen Zweige von lokalen und Remote-Refs (in meinem Beispiel von origin).

Jan Winter
quelle