Wymień wszystkie lokalne oddziały bez pilota

91

Problem: Chcę sposobu na usunięcie wszystkich lokalnych oddziałów, które mam, a które nie mają pilota. Łatwo jest przelać nazwy gałęzi do a git branch -D {branch_name}, ale jak w pierwszej kolejności uzyskać tę listę?

Na przykład:

Tworzę nowy oddział bez pilota:

$ git co -b no_upstream

Wymieniam wszystkie moje oddziały, a tylko jeden ma pilota

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

Jakie polecenie mogę uruchomić, aby otrzymać no_upstreamodpowiedź?

Mogę biec git rev-parse --abbrev-ref --symbolic-full-name @{u}i to pokaże, że nie ma pilota:

$ 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>...]'

Ale ponieważ jest to błąd, nie pozwala mi go używać ani przesyłać do innych poleceń. Zamierzam użyć tego jako aliasu skryptu powłoki git-delete-unbranchedlub może stworzyć super prosty klejnotgit-branch-delete-orphans

JC Denton
źródło

Odpowiedzi:

103

Niedawno odkryłem, git branch -vvktóra wersja git branchpolecenia jest „bardzo szczegółowa” .

Wyprowadza gałęzie wraz z gałęziami zdalnymi, jeśli istnieją, w następującym formacie:

  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

Po uzyskaniu tego ładnie sformatowanego wyjścia jest tak proste, jak przepuszczenie go przez potok cuti awkpobranie listy:

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

Daje następujące wyniki:

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

cutCzęść tylko normalizuje dane poprzez usunięcie dwóch pierwszych znaków (łącznie *) z wyjściem przed przekazaniem go do awk.

awkCzęść drukuje pierwszej kolumny, jeśli nie ma kwadratowy uchwyt w trzeciej kolumnie.

Bonus: utwórz alias

Ułatw sobie uruchomienie, tworząc alias w .gitconfigpliku globalnym (lub gdziekolwiek):

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

Ważne: odwrotny ukośnik musi zostać zmieniony w aliasie, w przeciwnym razie będziesz mieć nieprawidłowy plik gitconfig.

Bonus: zdalne filtrowanie

Jeśli z jakiegoś powodu masz wiele pilotów śledzących dla różnych oddziałów, łatwo jest określić, z którym pilotem chcesz sprawdzić. Wystarczy dołączyć zdalną nazwę do wzorca awk. W moim przypadku jest origintak, że mogę to zrobić:

git branch -vv | cut -c 3- | awk '$3 !~/\[origin/ { print $1 }'
Jeremy Baker
źródło
co to WIP:właściwie jest ..? czy to nie jest to, co tworzy polecenie skrytki ..?
igrek
@igrek To tylko przedrostek, którego użyłem w komunikacie dotyczącym zatwierdzenia. Nic specyficznego dla git.
Jeremy Baker
kiedy to zrobię git branch -vv, nawet jeśli zdalny oddział istnieje i pasuje do mojego lokalnego oddziału, nie zobaczyłbym [origin/branch-name]obok wyniku. Musiałem mieć diffdwie listy oddziałów, aby dowiedzieć się, co jest tylko lokalne.
ryantuck
git branch -vv | grep -v origin/wystarczy mi
nie panikuj
2
Czy to nie pomija zaznaczonych odległych gałęzi gone?
Reid
36

git branch (bez żadnych opcji) wyświetla tylko lokalne oddziały, ale nie wiesz, czy śledzą zdalny oddział, czy nie.

Zwykle te lokalne gałęzie powinny zostać usunięte po scaleniu master(jak widać w tym numerze git-sweep ):

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

To nie jest tak kompletne, jak chcesz, ale to początek.

W przypadku --merged, na liście zostaną wymienione tylko gałęzie włączone do nazwanego zatwierdzenia (tj. Gałęzie, których zatwierdzenia wskazujące są osiągalne z podanego zatwierdzenia).

VonC
źródło
1
Aby uwzględnić również oddziały zdalne bez oddziału lokalnego, użyj git branch -a --merged.
Acumenus
21

Mam podobny problem. Chcę usunąć wszystkie oddziały lokalne, które śledziły oddziały zdalne, które są teraz usuwane. Stwierdzam, że git remote prune originto nie wystarczyło, aby usunąć gałęzie, które chcę usunąć. Po usunięciu pilota chcę, aby lokalny również zniknął. Oto, co zadziałało dla mnie:

Z mojego ~/.gitconfig:

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

Oto git config --global ...polecenie umożliwiające łatwe dodanie tego jako 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'

UWAGA : Zmieniłem -dsię -Dw mojej aktualnej konfiguracji, bo nie chcą słyszeć Git narzekać oddziałów niescalonych. Państwo może chcieć tę funkcjonalność, jak również. Jeśli tak, po prostu użyj -Dzamiast -dna końcu tego polecenia.

Ponadto, FWIW, twój globalny plik konfiguracyjny prawie zawsze będzie ~/.gitconfig.

(Poprawka OS X)

Jak napisano, to nie działa na OS X ze względu na użycie xargs -r(dzięki, Korny ).

Ma -rto zapobiec xargsuruchomieniu git branch -dbez nazwy gałęzi, co spowoduje wyświetlenie komunikatu o błędzie „ fatal: branch name required”. Jeśli nie przeszkadza Ci komunikat o błędzie, możesz po prostu usunąć -rargument do xargsi gotowe.

Jeśli jednak nie chcesz widzieć komunikatu o błędzie (i naprawdę, kto może cię winić), będziesz potrzebować czegoś innego, co sprawdza, czy nie ma pustej potoki. Jeśli możesz użyć ifne z moreutils . Wstawiłbyś ifnewcześniej xargs, co przestanie xargsdziałać z pustymi danymi. UWAGA : ifneuważa, że cokolwiek nie jest puste, obejmuje to puste wiersze, więc nadal możesz zobaczyć ten komunikat o błędzie. Nie testowałem tego na OS X.

Oto ta git configlinia z 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
źródło
1
Czy można to przekonwertować na polecenie „git config --global ...”? Z punktu widzenia instrukcji / how-to-wiki-for-dummies łatwo jest przejść dalej, zamiast mówić „Znajdź swoje pliki konfiguracyjne git, użyj edytora, aby je edytować, a następnie uruchom polecenia”
Kannan Ekanath
Zauważ, że xargs -r nie działa na OSX
Korny
Dobrze wiedzieć. Nie wiem, jaka byłaby opcja „nie uruchamiaj, jeśli puste” dla OSX.
Karl Wilbur
18

Późna edycja:

Lepiej jest

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

Na GNU / cokolwiek

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

Gdyby było więcej niż kilka gałęzi, byłyby lepsze sposoby, używając comm -23do wyjścia git branch|sed|sorti git config -l|sed|sort.

jthill
źródło
1
@nmr s / git. * Q1 / test $ (git config --get branch. $ b.remote | sed q | wc -1) = 1 /
jthill
15

To działa dla mnie:

git branch -vv | grep -v origin

(jeśli twój pilot nosi inną nazwę niż pochodzenie, zastąp ją).

Spowoduje to wyświetlenie wszystkich gałęzi, które nie śledzą pilota, co brzmi jak to, czego szukasz.

ebr
źródło
2
Spowoduje to wyświetlenie gałęzi, które miały pilota, ale już go nie ma, nawet jeśli uruchomiłeś git fetch --prune.
RusinaRange
2
IMO, lepiej szukać „: gone]” zamiast odfiltrowywać „origin”
fiorentinoing
4

Syntetyzuję własne polecenie Git, aby uzyskać origin/***: gonegałęzie:

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 wypisze gałęzie w trybie szczegółowym.

cut -c 3- usunie pierwsze znaki.

grep ': gone]'wydrukuje tylko utracone zdalne gałęzie.

awk '{print $1}' wypisze nazwę gałęzi.

xargs -n1 -r echo git branch -dwypisze git branch -dpolecenie usunięcia gałęzi (-n1 będzie zarządzać jednym poleceniem na raz, -r, aby uniknąć wydania polecenia, jeśli nie ma żadnej gałęzi).

WSKAZÓWKA: usuń polecenie "echo", aby uruchamiać polecenia zamiast tylko drukowania. Zostawiłem to w poleceniu, aby sprawdzić polecenia przed wydaniem polecenia git.

WSKAZÓWKA 2: wydawaj git branch -Dwtedy i tylko wtedy, gdy jesteś pewien, że chcesz usunąć niepołączone gałęzie

fiorentinoing
źródło
od tego zrobiłem mój osobisty git
fiorentinoing
1
To zdecydowanie najczystsze rozwiązanie, jakie znalazłem, fajne! Nigdy nie spędziłem czasu na nauce awk, nie wiedziałem, że możesz to zrobić.
adamjc
2

Oto coś, czego użyłem w PowerShell z komentarzami, aby wyjaśnić, co robi. Aby wyjaśnić, co się dzieje, nie użyłem żadnych skróconych poleceń PowerShell (aliasów). Nie krępuj się skompresować go do pożądanego poziomu tajemniczości :)

$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
źródło
0

Połączenie kilku istniejących odpowiedzi:

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

Na przykład:

$ 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
źródło