Listen Sie alle lokalen Niederlassungen ohne Fernbedienung auf

88

Problem: Ich möchte alle lokalen Zweige löschen, die keine Fernbedienung haben. Es ist leicht genug, die Namen der Zweige in eine zu leiten git branch -D {branch_name}, aber wie bekomme ich diese Liste überhaupt?

Beispielsweise:

Ich erstelle einen neuen Zweig ohne Fernbedienung:

$ git co -b no_upstream

Ich liste alle meine Filialen auf und es gibt nur eine mit einer Fernbedienung

$ git branch -a
master
* no_upstream
remotes/origin/HEAD -> origin/master
remotes/origin/master

Welchen Befehl kann ich ausführen, um no_upstreameine Antwort zu erhalten?

Ich kann laufen git rev-parse --abbrev-ref --symbolic-full-name @{u}und das wird zeigen, dass es keine Fernbedienung hat:

$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Da dies jedoch ein Fehler ist, kann ich ihn nicht verwenden oder an andere Befehle weiterleiten. Ich beabsichtige, dies entweder als Alias ​​für ein Shell-Skript zu verwenden git-delete-unbranchedoder vielleicht ein supereinfaches Gem zu erstellengit-branch-delete-orphans

JC Denton
quelle
1
Mögliches Duplikat von Lokale Zweige entfernen nicht mehr auf Remote
ks1322

Antworten:

101

Ich habe kürzlich herausgefunden, git branch -vvwelche "sehr ausführliche" Version des git branchBefehls ist.

Es gibt die Zweige zusammen mit den entfernten Zweigen, falls vorhanden, im folgenden Format aus:

  25-timeout-error-with-many-targets    206a5fa WIP: batch insert
  31-target-suggestions                 f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link                      b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
  65-digest-double-publish              2de4150 WIP: publishing-state

Sobald Sie diese schön formatierte Ausgabe haben, ist es so einfach, sie durchzuleiten cutund awkIhre Liste zu erhalten:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'

Ergebnisse in der folgenden Ausgabe:

25-timeout-error-with-many-targets
65-digest-double-publish

Der cutTeil normalisiert nur die Daten, indem die ersten beiden Zeichen (einschließlich *) aus der Ausgabe entfernt werden, bevor sie an übergeben werden awk.

Der awkTeil druckt die erste Spalte, wenn in der dritten Spalte keine eckige Klammer vorhanden ist.

Bonus: Erstellen Sie einen Alias

Erleichtern Sie die Ausführung, indem Sie einen Alias ​​in Ihrer globalen .gitconfigDatei (oder wo auch immer) erstellen:

[alias]
  local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'

Wichtig: Der Backslash muss im Alias ​​maskiert werden, sonst haben Sie eine ungültige gitconfig-Datei.

Bonus: Fernfilterung

Wenn Sie aus irgendeinem Grund mehrere Tracking-Fernbedienungen für verschiedene Zweige haben, können Sie leicht angeben, gegen welche Fernbedienung Sie prüfen möchten. Hängen Sie einfach den Remote-Namen an das awk-Muster an. In meinem Fall ist es originso, dass ich das tun kann:

git branch -vv | cut -c 3- | awk '$3 !~/\[origin/ { print $1 }'
Jeremy Baker
quelle
was ist das überhaupt WIP:..? Ist es nicht das, was ein Stash-Befehl erzeugt?
Igrek
@igrek Das ist nur ein Präfix, das ich in der Commit-Nachricht verwendet habe. Nichts spezielles für Git.
Jeremy Baker
Wenn ich dies tue git branch -vv, würde ich das [origin/branch-name]neben dem Ergebnis nicht sehen, selbst wenn ein entfernter Zweig vorhanden ist und mit meinem lokalen Zweig übereinstimmt . Ich musste diffzwei Branchenlisten erstellen, um herauszufinden, was nur lokal war.
Ryantuck
git branch -vv | grep -v origin/ist genug für mich
keine Panik
2
Vermisst dies nicht die markierten entfernten Zweige gone?
Reid
36

git branch (ohne Optionen) listet nur lokale Zweige auf, aber Sie wissen nicht, ob sie einen entfernten Zweig verfolgen oder nicht.

Normalerweise sollten diese lokalen Zweige nach dem Zusammenführen gelöscht werden master(wie in dieser Ausgabe von git-sweep zu sehen ):

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

Dies ist nicht so vollständig wie Sie möchten, aber es ist ein Anfang.

Mit --mergedwerden nur Zweige aufgelistet, die mit dem benannten Commit zusammengeführt wurden (dh die Zweige, deren Spitzen-Commits über das benannte Commit erreichbar sind).

VonC
quelle
1
Verwenden Sie diese Option, um auch Remote-Zweige ohne lokalen Zweig einzuschließen git branch -a --merged.
Acumenus
21

Ich habe ein ähnliches Problem. Ich möchte alle lokalen Zweige entfernen, die entfernte Zweige verfolgen, die jetzt gelöscht werden. Ich stelle fest, dass dies git remote prune originnicht ausreichte, um die Zweige zu entfernen, die ich entfernen möchte. Sobald die Fernbedienung gelöscht ist, möchte ich, dass auch die lokale entfernt wird. Folgendes hat bei mir funktioniert:

Von meinem ~/.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 : Ich änderte die -dzu -Dmeiner aktuellen Konfiguration, weil ich nicht wollen , Git hören über unmerged Zweige beschweren. Sie können auch diese Funktionalität wünschen. Wenn ja, verwenden Sie einfach -Dstatt -dam Ende dieses Befehls.

Außerdem, FWIW, wäre Ihre globale Konfigurationsdatei fast immer ~/.gitconfig.

(OS X Fix)

Wie geschrieben, funktioniert dies unter OS X aufgrund der Verwendung von xargs -r(danke, Korny ) nicht.

Das -rist zu verhindern , dass die xargsAusführung von git branch -dohne Zweignamen, die in einer Fehlermeldung werden „ fatal: branch name required“. Wenn Ihnen die Fehlermeldung nichts ausmacht, können Sie das -rArgument einfach entfernen xargsund schon sind Sie fertig.

Wenn Sie jedoch keine Fehlermeldung sehen möchten (und wer könnte Ihnen die Schuld geben), benötigen Sie etwas anderes, das nach einer leeren Pipe sucht. Wenn Sie in der Lage sein könnten, ifne von moreutils zu verwenden . Sie würden ifnevorher einfügen xargs, wodurch die xargsAusführung mit leeren Daten beendet wird. HINWEIS : ifneBetrachtet alles als nicht leer. Dies schließt Leerzeilen ein, sodass diese Fehlermeldung möglicherweise weiterhin angezeigt wird. Ich habe dies nicht unter OS X getestet.

Hier ist diese git configZeile mit ifne:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'
Karl Wilbur
quelle
1
Ist es möglich, dies in einen Befehl "git config --global ..." umzuwandeln? Aus der Sicht von Anweisungen / Wiki-für-Dummies ist es einfach, weiterzugeben, anstatt zu sagen: "Finde deine Git-Konfigurationsdateien heraus, bearbeite sie mit dem Editor und
führe
Beachten Sie, dass xargs -r unter OSX nicht funktioniert
Korny
Gut zu wissen. Ich weiß nicht, was die Option "kein Ausführen, wenn leer" für OSX wäre.
Karl Wilbur
18

Späte Bearbeitung:

Besser ist

git for-each-ref  --format='%(refname:short) %(upstream)'  refs/heads \
| awk '$2 !~/^refs\/remotes/'

Auf GNU / irgendetwas

for b in `git branch|sed s,..,,`; do
    git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done

Wenn mehr als eine Handvoll Zweige wahrscheinlich wären, gäbe es bessere Möglichkeiten, comm -23die Ausgabe von git branch|sed|sortund zu nutzen git config -l|sed|sort.

jthill
quelle
1
@nmr s / git. * Q1 / test $ (git config --get branch. $ b.remote | sed q | wc -1) = 1 /
jthill
14

Das funktioniert bei mir:

git branch -vv | grep -v origin

(Wenn Ihre Fernbedienung einen anderen Namen als origin hat, ersetzen Sie diesen).

Dadurch werden alle Zweige aufgelistet, die keine Fernbedienung verfolgen. Dies klingt nach dem, wonach Sie suchen.

ebr
quelle
2
Dadurch werden Zweige aufgelistet, die früher eine Fernbedienung hatten, aber nicht mehr, selbst wenn Sie ausgeführt werden git fetch --prune.
RusinaRange
2
IMO, es ist besser, nach ": away]" zu suchen, als "origin" herauszufiltern
fiorentinoing
3

Ich synthetisiere meinen eigenen Git-Befehl, um die origin/***: goneZweige zu erhalten:

git remote prune origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d

git remote prune origin && git branch -vv druckt Zweige im ausführlichen Modus.

cut -c 3- entfernt die ersten Zeichen.

grep ': gone]'druckt nur die verschwundenen entfernten Zweige.

awk '{print $1}' druckt den Filialnamen.

xargs -n1 -r echo git branch -ddruckt den git branch -dBefehl zum Entfernen von Zweigen (-n1 verwaltet jeweils einen Befehl, -r, um die Ausgabe eines Befehls zu vermeiden, wenn kein Zweig vorhanden ist).

TIPP: Entfernen Sie den Befehl "echo", um die Befehle auszuführen, anstatt nur zu drucken. Ich habe diesen Befehl im Befehl belassen, um die Befehle vor der Ausgabe an git zu überprüfen.

TIPP 2: Problem git branch -Dgenau dann, wenn Sie sicher sind, dass Sie nicht zusammengeführte Zweige entfernen möchten

Fiorentinoing
quelle
von diesem habe ich mein persönliches git weg gemacht
fiorentinoing
2

Hier ist etwas, das ich in PowerShell mit Kommentaren verwendet habe, um zu erklären, was es tut. Um zu verdeutlichen, was los ist, habe ich keine abgekürzten PowerShell-Befehle (Aliase) verwendet. Fühlen Sie sich frei, es auf Ihr gewünschtes Maß an Kryptizität zu komprimieren :)

$verboseList = @(git branch -vv)
foreach ($line in $verboseList)
{
    # Get the branch name
    $branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
    # Check if the line contains text to indicate if the remote is deleted
    $remoteGone = $line.Contains(": gone]")
    # Check if the line does not contain text to indicate it is a tracking branch (i.e., it's local)
    $isLocal = !($line.Contains("[origin/"))
    if ($remoteGone -or $isLocal)
    {
        # Print the branch name
        $branch
    }
}
grahamesd
quelle
0

Einige der vorhandenen Antworten kombinieren:

[alias]
        branch-local = !git branch -vv | cut -c 3- | egrep '([0-9a-f]{7} [^[])|(: gone\\])' | sed -E 's/(^.+[0-9a-f]{7} (\\[.+\\])?).*$/\\1/'

Z.B:

$ git branch-local
autogen_autoreconf      fcfb1c6 [github/autogen_autoreconf: gone]
autotools_documentation 72dc477 [github/autotools_documentation: gone]
cray-mpich-messy        2196f4b
epel-sphinx             cfda770
lammps                  07d96a7 [github/lammps: gone]
lark-error              9ab5d6c [github/lark-error: gone]
no-root2                c3894d1
openmpi-cray            69326cf [github/openmpi-cray: gone]
shellcheck-cleanup      40d90ec
travis-python36         cde072e
update_vagrant_default  4f69f47 [github/update_vagrant_default: gone]
web-docs                e73b4a8
Reid
quelle