Usuń wszystkie lokalne gałęzie git

323

Śledzę proces rozwoju, w którym tworzę nowy oddział lokalny dla każdej nowej funkcji lub karty opowieści. Po zakończeniu łączę gałąź w master, a następnie pcham.

To, co dzieje się z czasem z powodu połączenia lenistwa lub zapomnienia, polega na tym, że kończę z dużą listą lokalnych oddziałów, z których niektóre (takie jak kolce) mogły nie zostać połączone.

Wiem, jak wyświetlić listę wszystkich moich lokalnych oddziałów i wiem, jak usunąć pojedynczy oddział, ale zastanawiałem się, czy istnieje polecenie git, które pozwala mi usunąć wszystkie moje lokalne oddziały?

Poniżej znajduje się wynik git branch --mergedpolecenia.

user@machine:~/projects/application[master]$ git branch --merged
  STORY-123-Short-Description
  STORY-456-Another-Description
  STORY-789-Blah-Blah
* master

Wszystkie próby usunięcia oddziałów wymienionych grep -v \*(zgodnie z odpowiedziami poniżej) powodują błędy:

error: branch 'STORY-123-Short-Description' not found.
error: branch 'STORY-456-Another-Description' not found.
error: branch 'STORY-789-Blah-Blah' not found.

Używam:
git 1.7.4.1
Ubuntu 10.04
GNU bash, wersja 4.1.5 (1) - wydanie
GNU grep 2.5.4

Louth
źródło
7
Błagam, przyjmij odpowiedź @Andrew!
Robert Siemer
@ GiulioCaccin Pytanie dotyczy również oddziałów, które mogły nie zostać połączone, a ja zaktualizowałem pytanie, aby wyraźnie to odzwierciedlić.
Louth

Odpowiedzi:

384

Podkomenda „git branch -d” może usunąć więcej niż jedną gałąź. Upraszczając odpowiedź @ sblom, ale dodając krytyczne xargs:

git branch -D `git branch --merged | grep -v \* | xargs`

lub dodatkowo uproszczone do:

git branch --merged | grep -v \* | xargs git branch -D 

Co ważne, jak zauważył @AndrewC, odradza się korzystanie git branchze skryptów. Aby tego uniknąć, użyj czegoś takiego:

git for-each-ref --format '%(refname:short)' refs/heads | grep -v master | xargs git branch -D

Należy zachować ostrożność podczas usuwania!

$ mkdir br
$ cd br; git init
Initialized empty Git repository in /Users/ebg/test/br/.git/
$ touch README; git add README; git commit -m 'First commit'
[master (root-commit) 1d738b5] First commit
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git branch Story-123-a
$ git branch Story-123-b
$ git branch Story-123-c
$ git branch --merged
  Story-123-a
  Story-123-b
  Story-123-c
* master
$ git branch --merged | grep -v \* | xargs
Story-123-a Story-123-b Story-123-c
$ git branch --merged | grep -v \* | xargs git branch -D
Deleted branch Story-123-a (was 1d738b5).
Deleted branch Story-123-b (was 1d738b5).
Deleted branch Story-123-c (was 1d738b5).
GoZoner
źródło
To polecenie nadal zgłasza takie same błędy, jak wspomniano w komentarzach do odpowiedzi poniżej. error:branch 'STORY-123-Short-Description' not found.dla każdej z wymienionych gałęzi.
Louth
1
Pracuje dla mnie; patrz wyżej z dodanymi szczegółami.
GoZoner
1
Czy używanie git 1.7.10 rozwiązało problem, czy wolisz pracować bezpośrednio w repozytorium .git?
GoZoner
1
Jeśli pojawi się error:branch 'STORY-123-Short-Description' not found.błąd, prawdopodobnie wynika to z ustawień kolorów git. To zadziałało dla mnie (zwróć uwagę na --no-coloropcję):git branch --no-color --merged | grep -v \* | xargs git branch -D
marcok
3
Jedyna odpowiedź na SO, którą znalazłem, działa. Dziękuję Ci!
Kevin Suttle
140

Znalazłem lepszy sposób w komentarzu na ten temat na github :

git branch --merged master --no-color | grep -v master | grep -v stable | xargs git branch -d

edycja: dodana opcja bezbarwna i wykluczająca stabilną gałąź (dodaj inne gałęzie w razie potrzeby)

mBardos
źródło
2
Wreszcie rozwiązanie, którego potrzebowałem
Code Whisperer
1
Próbowałem tego, ale wciąż dostaję error: branch 'my-branch-name' not found.dla każdej gałęzi. Korzystanie z gita w wersji 1.8.3.4 (Apple Git-47). Masz pomysł, dlaczego?
wheresrhys
spróbuj 'git branch --merged master | grep -v master | xargs echo 'do debugowania, co dokładnie próbuje usunąć? nie mam lepszych pomysłów ...
mBardos
2
Więc. git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
Павел Тявин
1
Nauczyłem się korzystać z xargs wraz z tym. Dzięki
Volem 12.04.17
105

Analiza wyników git branchnie jest zalecana i nie jest dobrą odpowiedzią dla przyszłych czytelników na temat przepełnienia stosu.

  1. git branchto tak zwane polecenie porcelany. Polecenia porcelany nie są przeznaczone do parsowania maszynowego, a dane wyjściowe mogą się zmieniać między różnymi wersjami Git.
  2. Istnieją opcje konfiguracji użytkownika, które zmieniają dane wyjściowe git branchw sposób, który utrudnia ich analizę (na przykład kolorowanie). Jeśli użytkownik ustawił color.branch, otrzymasz kody sterujące na wyjściu, to doprowadzi do tego, error: branch 'foo' not found.jeśli spróbujesz potokować go do innego polecenia. Możesz to obejść za pomocą --no-colorflagi git branch, ale kto wie, do czego mogą doprowadzić inne konfiguracje użytkowników.
  3. git branch może robić inne rzeczy, które irytujące podczas analizowania, takie jak umieszczenie gwiazdki obok aktualnie wyewidencjonowanego oddziału

Opiekunem git ma do powiedzenia na temat skryptów wokół git branchwyjścia

Aby dowiedzieć się, jaka jest obecna gałąź, przypadkowi / nieostrożni użytkownicy mogli pisać skrypt wokół gałęzi git, co jest błędem. Aktywnie odradzamy stosowanie w skryptach jakiegokolwiek polecenia Porcelain, w tym gałęzi git, ponieważ dane wyjściowe polecenia mogą ulec zmianie, aby pomóc w przypadku użycia przez ludzi.

Odpowiedzi sugerujące ręczne edytowanie plików w .git katalogu (takie jak .git / refs / heads) są podobnie problematyczne (referencje mogą być w .git / pack-refs, lub Git może zmienić ich wewnętrzny układ w przyszłości).

Git zapewnia for-each-ref polecenie pobrania listy gałęzi.

Git 2.7.X wprowadzi tę --mergedopcję, abyś mógł zrobić coś takiego jak poniżej, aby znaleźć i usunąć wszystkie połączone gałęzieHEAD

for mergedBranch in $(git for-each-ref --format '%(refname:short)' --merged HEAD refs/heads/)
do
    git branch -d ${mergedBranch}
done

W wersji Git 2.6.X i starszych musisz wyświetlić listę wszystkich lokalnych oddziałów, a następnie przetestować je indywidualnie, aby sprawdzić, czy zostały scalone (co będzie znacznie wolniejsze i nieco bardziej skomplikowane).

for branch in $(git for-each-ref --format '%(refname:short)' refs/heads/)
do
    git merge-base --is-ancestor ${branch} HEAD && git branch -d ${branch}
done
Andrew C.
źródło
git branch --no-color 2>/dev/null?
nobar
5
To na pewno poprawa. Zawsze będziesz miał problem z koniecznością odfiltrowania *, i to zabawne, jeśli ktoś uruchomi go z odłączonej głowy. Głównym problemem git branchjest jednak polecenie porcelany i nie ma gwarancji, że dane wyjściowe nie zmienią się w niektórych przyszłych wersjach git.
Andrew C
Dziękuję @AndrewC - to jest odpowiedź na pytanie dotyczące tajemniczych błędów „nie znaleziono gałęzi” i zapewnia działające rozwiązanie za pomocą bardziej odpowiedniego polecenia! 👍
Jason
2
W jaki sposób identyfikowane są polecenia GIT „Porcelana” i „Porcelana”?
GoZoner
1
Prawdopodobnie byłoby przydatnym rozszerzeniem domyślnie wykluczającym „dev” i „master”?
PandaWood,
66

Prostszy sposób na usunięcie wszystkich gałęzi z zachowaniem innych, takich jak „rozwijaj” i „master”, jest następujący:

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

bardzo przydatne !

geoom
źródło
8
Wskrzesiłeś odwieczny wątek i umieściłeś praktycznie identyczną odpowiedź na istniejącą, która jest błędna i brakuje jej zmian bezpieczeństwa. To nie jest dobra odpowiedź.
Andrew C
6
Ta odpowiedź jest jasna w potokowaniu danych wyjściowych z gałęzi git, modyfikowaniu jej i przekazywaniu do gałęzi git -D. Nie musisz być wredny.
Pam
To rozwiązanie działało dla mnie. Usunięto wszystkie lokalne oddziały.
Prad
1
Nie spowoduje to usunięcia żadnej gałęzi zawierającej słowo develop lub master jak „develop_feature” lub „master_feature”.
django,
TO ODPOWIEDŹ, NA KTÓREJ SZUKAM 👆🏻
Konrad G
62

Aby usunąć każdą gałąź oprócz tej, którą obecnie wypisałeś:

for b in `git branch --merged | grep -v \*`; do git branch -D $b; done

Polecam zmianę git branch -D $bdo echo $bpierwszych kilka razy, aby upewnić się, że usuwa gałęzie, które zamierzają.

sblom
źródło
1
dzięki temu poleceniu error:branch 'a_branch_name' not found.widzę, co próbujesz zrobić, i bawiłem się tym poleceniem, ale z jakiegoś powodu git nie lubi podanych nazw gałęzi ...
Louth
hmmm. aby pomóc w rozwiązywaniu problemów, dobrze byłoby zobaczyć przykładowe dane wyjściowe zgit branch --merged
sblom
moje nazwy oddziałów mają formatSTORY-123-Short-Description
Louth
a kiedy biegniesz git branch --merged, masz listę z jednym z nich w każdej linii?
sblom
1
czy to dosłownie mówi error:branch 'a_branch_name' not found.? Czy może narzeka na jedną z nazw gałęzi z twojego git branchwyjścia powyżej?
sblom
52

Poniższe polecenie usunie wszystkie gałęzie lokalne oprócz gałęzi master.

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

Powyższe polecenie

  1. wypisz wszystkie gałęzie
  2. Z listy zignoruj ​​gałąź główną i zabierz resztę gałęzi
  3. usuń gałąź
Łowca
źródło
4
Chciałbym użyć git branch | grep -v "master" | xargs git branch -dnajpierw, aby nie usuwać nie połączonych gałęzi, tylko dla bezpieczeństwa. Ale miła odpowiedź!
Jonas Lomholdt
3
Oto wersja PowerShell,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
Jonas Lomholdt
1
@ baklazan działałoby to tylko w wierszu poleceń systemu Windows 10, jeśli masz zainstalowane jakieś narzędzia. Prawdopodobnie masz MINGW lub coś takiego i nie wiesz o tym.
KthProg,
42

Tylko uwaga, zaktualizowałbym do wersji git 1.7.10. Być może otrzymujesz odpowiedzi, które nie będą działać w twojej wersji. Domyślam się, że musiałbyś poprzedzić nazwę gałęzirefs/heads/ .

OSTROŻNIE, wykonaj następujące czynności tylko, jeśli wykonałeś kopię folderu roboczego i katalogu .git.

Czasami po prostu idę do przodu i usuwam gałęzie, których nie chcę od razu .git/refs/heads. Wszystkie te gałęzie są plikami tekstowymi zawierającymi 40 znaków sha-1 zatwierdzenia, na który wskazują. Będziesz mieć dodatkowe informacje, .git/configjeśli skonfigurowałeś określone śledzenie dla któregokolwiek z nich. Możesz również usunąć te wpisy ręcznie.

Adam Dymitruk
źródło
Nareszcie prosta i pragmatyczna opcja. Podoba mi się: D
Melvyn
2
To nie zadziała, jeśli masz spakowane referencje lub nawet jeśli czasami klonujesz ze zdalnego serwera (co zapewni ci spakowane pliki). Jeśli twoje referencje są spakowane, to referencje nie będą przechowywane w .git / refs / heads, będą przechowywane w pliku o nazwie „pack-refs”. Zobacz git-scm.com/docs/git-pack-refs .
Alexander Bird
1
Wydaje się, że to zły pomysł, aby usunąć gałąź, którą sprawdziłeś w tej chwili
Moberg
@Mergerg Po prostu sprawdź wcześniej zatwierdzenie, a odłączony HEAD będzie unosił się w porządku.
RomainValeri
34

Spróbuj wykonać następujące polecenie powłoki:

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

Wyjaśnienie:

  • 🛒 Pobierz wszystkie gałęzie za pomocą git branch | grep -v "master"polecenia
  • 👇 Wybierz każdą gałąź za pomocą xargspolecenia
  • 💦 Usuń gałąź za pomocą xargs git branch -D
Pravin
źródło
3
Chociaż może to być poprawna odpowiedź. Jedna linia kodu nie jest zbyt przydatna bez wyjaśnienia, co i jak rozwiązuje oryginalne pytanie. Podaj szczegóły swojej odpowiedzi.
RyanNerd
28

Aby usunąć wszystkie lokalne oddziały w systemie Linux oprócz tego, w którym jesteś

// hard delete

git branch -D $(git branch)
Ashish Yadav
źródło
2
Ten wydaje się bezpieczniejszy niż wchodzenie do .git i usuwanie rzeczy.
nelsontruran
25

Łatwiej było mi użyć edytora tekstu i powłoki.

  1. Wpisz git checkout <TAB>w powłoce. Pokaże wszystkie lokalne oddziały.
  2. Skopiuj je do edytora tekstu, usuń te, które musisz zachować.
  3. Zastąp podział linii spacjami. (W SublimeText jest to bardzo łatwe.)
  4. Otwórz powłokę, wpisz git branch -D <PASTE THE BRANCHES NAMES HERE>.

Otóż ​​to.

culebrón
źródło
Nie sądzę, że możesz usunąć gałąź, na której stoisz.
Dong Thang,
@Dong Obok tej gałęzi jest *, więc wystarczy usunąć go z skopiowanej listy!
Melanie
12

Miałem podobną sytuację i ostatnio uznałem następującą komendę za przydatną.

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep>/) printf "%s", $0 }'`

Jeśli chcesz zachować wiele oddziałów, to

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep1>|<Branch_You_Want_to_Keep2>/) printf "%s", $0 }'`

mam nadzieję, że to komuś pomoże.

4u.Ans
źródło
1
Fajny, ale potrzebowałem backticków, żeby działał - git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` Właściwie myślę, że pierwotnie je miałeś, ale zgubiły się w formatowaniu SO.
tassinari,
10

Z wiersza poleceń systemu Windows usuń wszystkie oprócz bieżącej wypisanej gałęzi, używając:

for /f "tokens=*" %f in ('git branch ^| find /v "*"') do git branch -D %f
kiewic
źródło
7

Jeśli nie musisz przechodzić przez sam Git, możesz także usunąć głowice w .git / refs / heads ręcznie lub programowo. Poniższe elementy powinny działać przy minimalnym ulepszeniu w Bash:

shopt -s extglob
rm -rf .git/refs/heads/!(master)

Spowoduje to usunięcie każdej gałęzi lokalnej z wyjątkiem gałęzi głównej. Ponieważ twoje odgałęzienia są przechowywane w .git / refs / piloty , pozostaną nietknięte.

Jeśli nie używasz Basha lub chcesz ponownie uruchomić wiele repozytoriów Git na raz, możesz zrobić coś podobnego z GNU find:

find . \
    -path remotes -path logs -prune -o \
    -wholename \*.git/refs/heads/\* \! -name master -print0 |
xargs -0 rm -rf

Rozwiązanie wyszukiwania jest prawdopodobnie bardziej przenośne, ale przycinanie ścieżek i nazw plików jest trudne i potencjalnie bardziej podatne na błędy.

Todd A. Jacobs
źródło
Fajne. Usunięcie wizualne :)
sandalone
5

Żadna z odpowiedzi nie spełniła w pełni moich potrzeb, więc zaczynamy:

git branch --merged | grep -E "(feature|bugfix|hotfix)/" | xargs git branch -D && git remote prune origin

Spowoduje to usunięcie wszystkich lokalnych oddziałów, które są scalone i zaczynają się od feature/, bugfix/lub hotfix/. Następnie pilot nadrzędnyorigin jest przycinany (może być konieczne podanie hasła).

Działa na Git 1.9.5.

użytkownik4401817
źródło
5

W oparciu o kombinację wielu odpowiedzi tutaj - jeśli chcesz zachować wszystkie gałęzie, które istnieją zdalnie, ale usunąć resztę , następujący oneliner załatwi sprawę:

git for-each-ref --format '%(refname:short)' refs/heads | grep -Ev `git ls-remote --quiet --heads origin | awk '{print substr($2, 12)}'| paste -sd "|" -` | xargs git branch -D
Srishan Bhattarai
źródło
3

Chociaż nie jest to rozwiązanie z linii poleceń, jestem zaskoczony graficznym interfejsem Git nie został jeszcze zasugerowany.

Korzystam z wiersza polecenia 99% czasu, ale w tym przypadku jest on albo zbyt wolny, by spowolnić (stąd pierwotne pytanie), albo nie wiesz, co zamierzasz usunąć, korzystając z długiej, ale sprytnej manipulacji powłoką.

Interfejs użytkownika rozwiązuje ten problem, ponieważ możesz szybko sprawdzić gałęzie, które chcesz usunąć, i otrzymać przypomnienie o tych, które chcesz zachować, bez konieczności wpisywania polecenia dla każdej gałęzi.

Z interfejsu użytkownika przejdź do Oddziału -> Usuń i Ctrl + Kliknij gałęzie, które chcesz usunąć, aby zostały podświetlone. Jeśli chcesz mieć pewność, że zostaną scalone w oddział (np. dev), W obszarze Usuń tylko, jeśli Scalono w Aby ustawić Oddział lokalny na dev. W przeciwnym razie ustaw opcję Zawsze, aby zignorować tę kontrolę.

GitUI: usuń lokalne oddziały

Dane Bouchie
źródło
1

W przypadku PowerShell będzie to działać:

git branch --format '%(refname:lstrip=2)' --merged `
    | Where-Object { $_ -ne 'master' } `
    | ForEach-Object { git branch -d $_ }
Lucas
źródło
0

Poniższy skrypt usuwa gałęzie. Użyj go i zmodyfikuj na własne ryzyko itp. Itp.

Opierając się na innych odpowiedziach w tym pytaniu, napisałem dla siebie szybki skrypt bash. Nazwałem go „gitbd” (gałąź git -D), ale jeśli go użyjesz, możesz zmienić nazwę na dowolną.

gitbd() {
if [ $# -le 1 ]
  then
    local branches_to_delete=`git for-each-ref --format '%(refname:short)' refs/heads/ | grep "$1"`
    printf "Matching branches:\n\n$branches_to_delete\n\nDelete? [Y/n] "
    read -n 1 -r # Immediately continue after getting 1 keypress
    echo # Move to a new line
    if [[ ! $REPLY == 'N' && ! $REPLY == 'n' ]]
      then
        echo $branches_to_delete | xargs git branch -D
    fi
else
  echo "This command takes one arg (match pattern) or no args (match all)"
fi
}

Będzie oferował usunięcie wszelkich gałęzi, które pasują do argumentu wzorca, jeśli zostaną przekazane, lub wszystkich gałęzi lokalnych, gdy zostaną wywołane bez argumentów. To również da ci krok potwierdzający, ponieważ, wiesz, usuwamy rzeczy, więc to miłe.

To trochę głupie - jeśli nie ma gałęzi pasujących do wzoru, nie zdaje sobie z tego sprawy.

Przykładowy przebieg wyjściowy:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 
dherman
źródło
0

Napisałem skrypt powłoki, aby usunąć wszystkie lokalne gałęzie oprócz develop

branches=$(git branch | tr -d " *")
output=""
for branch in $branches 
do
  if [[ $branch != "develop" ]]; then
    output="$output $branch"
  fi
done
git branch -d $output
nhp
źródło
0

Powyższe odpowiedzi działają dobrze. Oto inne podejście, gdy mamy wiele gałęzi w lokalnym repozytorium i musimy usunąć wiele gałęzi z wyjątkiem kilku, które leżą na lokalnej maszynie.

Pierwszy git branch wyświetli listę wszystkich lokalnych oddziałów.

Aby przetransponować kolumnę z nazwami gałęzi do pojedynczego wiersza w pliku, uruchamiając polecenie unix.
git branch > sample.txt
Zostanie to zapisane w pliku sample.txt . I biegnij
awk 'BEGIN { ORS = " " } { print }' sample.txt
polecenie w powłoce. Spowoduje to przekształcenie kolumny w wiersz i skopiowanie listy nazw gałęzi w jednym wierszu.

A potem biegnij
git branch -D branch_name(s).
Spowoduje to usunięcie wszystkich wymienionych oddziałów obecnych w lokalnym

Deepak G.
źródło
0

Najbardziej pragmatyczny sposób: upewnij się, że nie masz nieproszonej pracy master, zatwierdzaj / wypychaj w razie potrzeby, klonuj nową kopię repozytorium i usuń starą.

Patrick Sanan
źródło
0

W tym celu możesz użyć dodatków git

$ git delete-merged-branches
Deleted feature/themes (was c029ab3).
Deleted feature/live_preview (was a81b002).
Deleted feature/dashboard (was 923befa).
Andrij Orehov
źródło
0

Nie mam grep ani innego Uniksa na moim urządzeniu, ale działało to z terminalu VSCode:

git branch -d $(git branch).trim()

Używam małych liter d, aby nie usuwać nie połączonych gałęzi.

Byłem też na masterie, kiedy to zrobiłem, więc * masternie istnieje, więc nie próbował usunąć master.

Ron Newcomb
źródło
Potwierdzony: Jeśli nie jest włączony master, to polecenie BĘDZIE usunięte master.
Brett Rowberry
-1

Najpierw upewnij się, że to robisz

git fetch

Po uzyskaniu wszystkich informacji o zdalnych gałęziach użyj następującego polecenia, aby usunąć każdą gałąź oprócz master

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
Meng
źródło