Czyszczenie starych zdalnych gałęzi git


694

Pracuję na dwóch różnych komputerach (A i B) i przechowuję wspólnego git zdalnego w katalogu dropbox.

Powiedzmy, że mam dwie gałęzie, master i devel. Oba śledzą swoje zdalne odpowiedniki origin / master i origin / devel.

Teraz na komputerze A usuwam rozwijanie gałęzi, lokalnie i zdalnie.

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

Uruchomiony git branch -ana komputerze, pojawia się następujący wykaz oddziałów.

  • mistrz
  • pochodzenie / HEAD
  • pochodzenie / mistrz

Działając git fetchna komputerze B, mogę usunąć lokalną gałąź rozwoju git branch -d devel, ale nie mogę usunąć zdalnej gałęzi rozwoju.

git push origin :heads/devel zwraca następujące komunikaty o błędach.

błąd: nie można przekazać do niekwalifikowanego miejsca docelowego: heads / proxy3d Refspec
docelowy nie pasuje do istniejącego ref na pilocie ani nie zaczyna się od ref /, i nie możemy zgadnąć prefiksu na podstawie referencji źródłowej.
fatal: Odległy koniec odłożył słuchawkę nieoczekiwanie

git branch -a wciąż wyświetla pochodzenie / rozwój w zdalnych gałęziach.

Jak mogę wyczyścić zdalne oddziały z komputera B?


4
Ten, kto tego próbował, powiedział mi, że repozytoria git w folderach Dropbox są nieco kruche (ale bez dodatkowych szczegółów).
Thorbjørn Ravn Andersen

5
@ ThorbjørnRavnAndersen prawdopodobnie dlatego, że musisz poczekać, aby zapewnić całkowitą synchronizację przy każdym zatwierdzeniu, zanim będziesz mieć pewność, że można bezpiecznie używać go na innym komputerze (i jeszcze wtedy wymagana jest kolejna synchronizacja).
ataulm

Odpowiedzi:


1240

Po pierwsze, jaki jest wynik git branch -ana maszynie B?

Po drugie, już usunięte heads/develna origin, więc dlatego nie można go usunąć z urządzenia B.

Próbować

git branch -r -d origin/devel

lub

git remote prune origin

lub

git fetch origin --prune

i możesz dodać --dry-runna końcu swojego gitoświadczenia, aby zobaczyć wynik jego uruchomienia bez faktycznego uruchomienia.

Dokumenty dla git remote prunei git branch.


50
git remote prune originpracował dla mnie => * [pruned] origin/my-old-branch
Hari Karam Singh

126
git remote prune origin --dry-runpokazuje, co zostanie usunięte bez robienia tego.
Wolfram Arnold

30
git fetch origin --prunebył idealny do usuwania usuniętych gałęzi
Sébastien Barbieri

10
Jeśli masz oddział lokalny, który śledzi pilota, którego już nie ma, niczego to nie usunie. Dla tych wydaje się, że git branch -vvnastępuje, git branch -D branchnamea na koniec śliwka jest najlepszym sposobem.
Roman Starkov

7
Możesz skonfigurować przycinanie, aby odbywało się automatycznie podczas pobierania / pobierania, ustawiając następującą opcję:git config remote.origin.prune true
Patrick James McDougle,

100

Rozważ uruchomienie:

git fetch --prune

Regularnie w każdym repozytorium, aby usunąć lokalne oddziały, które śledziły zdalną gałąź, która jest usuwana (już nie istnieje w zdalnej repozytorium GIT).

Można to dodatkowo uprościć

git config remote.origin.prune true

jest to per-repoustawienie, dzięki któremu każda przyszłość git fetch or git pullbędzie automatycznie przycinana .

Aby skonfigurować to dla użytkownika, możesz również edytować globalny plik .gitconfig i dodać

[fetch]
    prune = true

Zaleca się jednak wykonanie tej czynności za pomocą następującego polecenia:

git config --global fetch.prune true

lub zastosować go w całym systemie (nie tylko dla użytkownika)

git config --system fetch.prune true

14

Oto skrypt bash, który może to dla Ciebie zrobić. Jest to zmodyfikowana wersja skryptu http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git . Moja modyfikacja umożliwia obsługę różnych zdalnych lokalizacji.

#!/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

1
To zepsuło się na gałęzi o nazwie „origin / feature / mybranch”, nie jestem pewien dlaczego.
Stavros Korokithakis

Problem leży po obu sedstronach. Zastąpić sed 's/\(.*\)\/\(.*\)/\1/g'przezsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoit Latinier

14

Polecenie to „na sucho” usunie wszystkie zdalne ( origin) połączone gałęzie oprócz master. Możesz to zmienić lub dodać dodatkowe gałęzie po master: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

Jeśli wygląda dobrze, usuń --dry-run. Dodatkowo możesz najpierw przetestować to na widelcu.


Miły. Moje ulepszenie przy użyciu perla zamiast 1. xargs + awk: git branch -r --merged | pochodzenie grep | grep -v '>' | grep -v master | perl -lpe '($ śmieci, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin
Andrew

6

Jeśli git branch -rpokazuje wiele oddziałów zdalnego śledzenia, które nie są zainteresowane i chcesz je usunąć tylko z lokalnego, użyj następującego polecenia:

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

Bezpieczniejszą wersją byłoby usunięcie tylko scalonych:

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

Może to być przydatne w dużych projektach, w których nie potrzebujesz gałęzi funkcji innych członków drużyny, ale istnieje wiele gałęzi zdalnego śledzenia pobranych przy pierwszym klonie.

Jednak sam ten krok nie jest wystarczający, ponieważ te usunięte gałęzie zdalnego śledzenia wrócą później git fetch.

Aby zatrzymać pobieranie tych gałęzi zdalnego śledzenia, musisz jawnie określić odnośniki do pobrania w .git / config :

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

W powyższym przykładzie mamy tylko sprowadzić master, developi zwolnić oddziały, nie krępuj się dostosować, jak trzeba.


1
Dzięki, pierwsze polecenie zadziałało dla mnie. Możesz także pobrać tylko jedną gałąź git fetch origin branchnamelub utworzyć alias, ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"aby pobrać tylko bieżącą gałąź (mój osobisty ulubiony). Twoje zdrowie.
GiovanyMoreno

Może OT, ale co oznacza -rflaga? Widzę, że xargsma -Rkłótnię, ale nic nie znalazłem -r. Teoretycznie, jeśli dobrze pamiętam, jak to xargsdziała, nawet bez -rniego powinno działać.
Aldo „xoen” Giambelluca

Podoba mi się ta odpowiedź. Kilka notatek (stwierdzenie oczywistych rzeczy naprawdę). Możliwe jest „wyświetlenie podglądu” gałęzi, które zostaną usunięte, poprzez usunięcie ostatniego potoku i ostatniego polecenia | xargs git branch -d. Ponadto, usuwając -ropcję ( --remotes) z , usuwamy git branch -dtylko lokalne gałęzie (co może być wystarczające, biorąc pod uwagę, że domyślnie i git branchtak nie pokazują zdalnych gałęzi).
Aldo „xoen” Giambelluca

Dzięki! Właśnie tego potrzebowałem. Inne rozwiązania sugerują wypychanie przyciętych gałęzi lokalnych do pilota, aby je również usunąć, ale to nie pomaga, gdy pilot został usunięty lub już nie istnieje. Takie podejście usunęło lokalne odniesienia do zdalnych gałęzi, do których nie mam już dostępu.
cautionbug

@aldo, xargs -ra mianowicie --no-run-if-empty, oznacza to rozszerzenie GNU, oto miłe wytłumaczenie .
ryenus

4

Usuwanie jest zawsze trudnym zadaniem i może być niebezpieczne !!! Dlatego najpierw wykonaj następujące polecenie, aby zobaczyć, co się stanie:

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

Postępując w ten sposób jak wyżej, gitdostarczy ci listę tego, co by się stało, gdyby poniższe polecenie zostało wykonane.

Następnie uruchom następujące polecenie, aby usunąć wszystkie gałęzie ze zdalnego repozytorium, które nie znajdują się w lokalnym repozytorium:

git push --all --prune

10
To polecenie wydaje się niebezpieczne ... Udało mu się usunąć to, czego chciałem (i nie mogłem zrobić z co najmniej czterema powyższymi odpowiedziami). Ale usunęło również cztery inne gałęzie deweloperów. Git absolutnie do bani ...
jww

2
Te oddziały nie mogły znajdować się w Twojej okolicy. Jednak nie wszystko jest stracone. Git commit, Git reflog, a następnie git reset --hard <checksum>. Możesz dosłownie do każdego zatwierdzenia (inaczej zapisać) i innych z tym. Oddział to tylko etykieta, usunięcie etykiety nie powoduje usunięcia zapisu ... na zawsze będzie miała sumę kontrolną. Daj mi znać, jeśli mogę pomóc
Timothy LJ Stewart

3
Oczywiście, będziesz chciał je odzyskać dość szybko, ponieważ śmieciarz gita ostatecznie usunie zatwierdzenia, do których nie odwołują się gałęzie.
Andrew

1
Dobrze jest dodać -n(polecenie „na sucho”) do tego polecenia, aby wyświetlić podgląd zmian, a następnie, jeśli wszystko jest w porządku, wywołaj je ponownie bez -n.
mati865,

1
Zgadzam się z @GuiWeinmann - Jest to zbyt niebezpieczne, szczególnie bez konkretnego objaśnienia, aby przynajmniej uruchomić to najpierw na sucho.
Vivek M. Chawla

2

Oto jak to zrobić za pomocą SourceTree (v2.3.1):
1. Kliknij Pobierz
2. Zaznacz „Przycinaj gałęzie śledzenia ...”
3. Naciśnij OK
4. 😀

wprowadź opis zdjęcia tutaj


1

Muszę tu dodać odpowiedź, ponieważ inne odpowiedzi albo nie obejmują mojej sprawy, albo są niepotrzebnie skomplikowane. Używam github z innymi programistami i chcę tylko, aby wszystkie lokalne oddziały, których piloty zostały (prawdopodobnie połączone i) usunięte z PR github, zostały usunięte za jednym razem z mojej maszyny. Nie, rzeczy takie jak git branch -r --mergednie obejmują gałęzi, które nie zostały scalone lokalnie, lub tych, które w ogóle nie zostały scalone (porzucone) itp., Więc potrzebne jest inne rozwiązanie.

W każdym razie, pierwszy krok uzyskałem z innych odpowiedzi:

git fetch --prune

git remote prune originWydawało mi się, że próba na sucho zrobiłaby to samo w moim przypadku, więc wybrałem najkrótszą wersję, aby było to proste.

Teraz git branch -vnależy oznaczyć gałęzie, których piloty są usuwane jako [gone]. Dlatego wszystko, co muszę zrobić, to:

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

Tak proste, że usuwa wszystko, czego chcę dla powyższego scenariusza.

Mniej powszechna xargsskładnia polega na tym, że oprócz Linuksa działa również na komputerach Mac i BSD. Ostrożnie, to polecenie nie jest suchym przebiegiem, więc wymusi usunięcie wszystkich gałęzi oznaczonych jako [gone]. Oczywiście, że to git nic nie przepadnie na zawsze, jeśli zobaczysz, że gałęzie usunięte, o których pamiętasz, że chcesz je zachować, zawsze możesz je cofnąć (powyższe polecenie wyświetli ich skrót podczas usuwania, więc to proste git checkout -b <branch> <hash>.


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

Przycinaj te same gałęzie z lokalnych i zdalnych odnośników (w moim przykładzie z origin).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.