Wyświetlanie i usuwanie zatwierdzeń Git, które nie znajdują się w żadnej gałęzi (wiszące?)

146

Mam repozytorium Git z dużą ilością zatwierdzeń, które nie znajdują się w żadnej konkretnej gałęzi, mogę git showje zrobić , ale kiedy próbuję wyświetlić listę gałęzi, które je zawierają, nic nie informuje.

Myślałem, że jest to problem z wiszącymi zatwierdzeniami / drzewem (wynikający z gałęzi -D), więc przyciąłem repozytorium, ale nadal widzę to samo zachowanie po tym:

$ git fetch origin

$ git fsck --unreachable
$ git fsck

Brak wyjścia, nic nie zwisa (prawda?). Ale zatwierdzenie istnieje

$ git show 793db7f272ba4bbdd1e32f14410a52a412667042
commit 793db7f272ba4bbdd1e32f14410a52a412667042
Author: ...

i nie jest osiągalny przez żadną gałąź jako

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

nie daje wyjścia.

Jaki dokładnie jest stan tego zatwierdzenia? Jak mogę wymienić wszystkie zatwierdzenia w podobnym stanie? Jak mogę usunąć takie zmiany?

Samer Buna
źródło

Odpowiedzi:

75

Brak wyjścia, nic nie zwisa (prawda?)

Zauważ, że zatwierdzenia, do których odwołuje się Twój reflog, są uważane za osiągalne.

Jaki dokładnie jest stan tego zatwierdzenia? Jak mogę wymienić wszystkie zmiany o podobnym stanie

Podaj, --no-reflogsaby przekonać git fsckCię do ich pokazania.

Jak mogę usunąć takie zmiany?

Gdy Twoje wpisy reflog wygasną, te obiekty zostaną również wyczyszczone przez git gc.

Waży regulują gc.pruneexpire, gc.reflogexpireoraz gc.reflogexpireunreachableustawień. Por. git help config.

Wszystkie wartości domyślne są całkiem rozsądne.

Arystoteles Pagaltzis
źródło
2
więc w zasadzie mówisz, że ponowne przepływy dla wiszących zatwierdzeń zostaną automatycznie usunięte po chwili?
MoralCode
2
Zasadniczo: tak - poza tym, że pytanie jest nieco zagmatwane. Mówię, że wszystkie wpisy reflog są automatycznie usuwane po pewnym czasie, ale możesz to zmienić w ustawieniach konfiguracyjnych. A ponieważ zatwierdzenie jest nazywane dangling tylko wtedy, gdy nic do niego nie wskazuje - w tym wpisy reflog - „reflogs dla wiszących commits” nie są rzeczą. Byłyby „refleksjami na temat nieosiągalnych zatwierdzeń”.
Arystoteles Pagaltzis
„Byliby„ refleksjami na temat nieosiągalnych zobowiązań ”. Ale powiedziałeś: „zatwierdzenia, do których odwołuje się Twój reflog, są uważane za osiągalne”. Jak więc „reflogs dla nieosiągalnych zatwierdzeń” może być czymś? Jestem zmieszany.
LarsH
1
Tak, nie byłem konsekwentny. Zwykle ludzie nie myślą o reflogu, a kiedy mówią „nieosiągalny”, oznacza to „od osoby referencyjnej”. Nawet git help glossarydefiniuje to w ten sposób… podczas gdy jego definicja „osiągalnego” nie jest w ten sposób zawężona, więc są ze sobą sprzeczne. Zabawne - więc to, co powiedziałem, jest właściwie zgodne z zamieszaniem w gitglossary… To nie pojęcia są mylące, tylko terminologia. Chodzi o to, że „wiszące” zatwierdzenia to takie, na które nic innego nie wskazuje. Czy pomogłoby, gdybym powiedział „reflogs dla innych nieosiągalnych zatwierdzeń”…?
Arystoteles Pagaltzis
To wszystko jest bardzo zagmatwane. Uprośćmy to. Kiedy masterjesteś na gałęzi , robisz git commiti otrzymujesz zatwierdzenie 000001. Wtedy robisz git commit --amend, co daje ci zobowiązanie 000002. Nie ma już żadnych tagów ani gałęzi wskazujących na 000001, i nie możesz ich zobaczyć w swoim dzienniku bez --reflogopcji, ale jeśli chcesz, nadal możesz się do tego dostać za pomocą git checkout 000001. Teraz pytanie brzmi: czy jest 000001to wiszące zatwierdzenie, czy nieosiągalne zatwierdzenie, czy żadne z nich, czy jedno i drugie?
chharvey
264

Aby usunąć wszystkie wiszące zatwierdzenia i te dostępne z reflogów, wykonaj następujące czynności:

git reflog expire --expire-unreachable=now --all
git gc --prune=now

Ale upewnij się, że tego chcesz. Zalecam przeczytanie stron podręcznika, ale oto sedno:

git gcusuwa nieosiągalne obiekty (zatwierdzenia, drzewa, bloby (pliki)). Obiekt jest nieosiągalny, jeśli nie jest częścią historii jakiejś branży. Właściwie jest to trochę bardziej skomplikowane:

git gc robi inne rzeczy, ale nie są one tutaj istotne i nie są niebezpieczne.

Nieosiągalne obiekty młodsze niż dwa tygodnie nie są usuwane, więc używamy, --prune=nowco oznacza „usuń nieosiągalne obiekty, które zostały utworzone wcześniej”.

Obiekty mogą być również osiągane przez reflog. Podczas gdy gałęzie rejestrują historię niektórych projektów, reflogi rejestrują historię tych gałęzi. Jeśli zmienisz, zresetujesz itp., Zmiany zostaną usunięte z historii gałęzi, ale git zachowa je na wypadek, gdybyś zdał sobie sprawę, że popełniłeś błąd. Reflogs to wygodny sposób na sprawdzenie, jakie destrukcyjne (i inne) operacje zostały wykonane na gałęzi (lub HEAD), ułatwiając cofnięcie destrukcyjnej operacji.

Musimy więc również usunąć reflogs, aby faktycznie usunąć wszystko, co nie jest osiągalne z gałęzi. Robimy to poprzez wygasanie --allreflogów. Znowu git zachowuje nieco z reflogs aby chronić użytkowników, więc znowu trzeba powiedzieć to, aby nie zrobić tak: --expire-unreachable=now.

Ponieważ używam głównie reflogów do regeneracji po destrukcyjnych operacjach, zwykle używam --expire=nowzamiast tego, co całkowicie niszczy reflogs.

stęp
źródło
1
Powiem ci, jakich poleceń użyć, co nie jest oczywiste - czy gc nie powinno wystarczyć? Jeśli nigdy wcześniej nie używałeś git-reflog, nie będziesz wiedział. Więc teraz, gdy wiesz, jakich poleceń musisz użyć, powinieneś sprawdzić wspomniane opcje na ich stronach podręcznika. Oczywiście mógłbym zamiast tego po prostu skopiować te informacje ...
tarsius
1
Cóż, właściwie powiem dokładnie, co robi: „usuń wszystkie wiszące zmiany i te dostępne z reflogów”. Jeśli nie wiesz, czym są reflogi: ponownie przeczytaj instrukcję.
tarsius
7
Chociaż udzielona odpowiedź może być poprawna, @ erikb85 ma rację, wskazując, że nie było edukacji na temat tego, co ma zrobić. Dalsze korzystanie z RTFM jest jeszcze mniej pomocne. Tak, wszyscy powinniśmy przeczytać całą dokumentację. W niektórych przypadkach być może osoba wyszukująca nie zapoznaje się z dokumentacją na tyle, by wiedzieć, co się dzieje. Tak więc odrobina wiedzy na temat tego, co robią polecenia, byłaby pomocna dla każdego, kto później znajdzie tę odpowiedź.
Lee Saferite
@LeeSaferite mam nadzieję, że wszyscy jesteście teraz szczęśliwi :-)
tarsius
12
git reflog expire --expire-unreachable=now --allupuszcza wszystkie twoje skrytki!
Vsevolod Golovanov
22

Miałem ten sam problem, po wykonaniu wszystkich rad w tym wątku:

git reflog expire --expire-unreachable=now --all
git gc --prune=now
git fsck --unreachable --no-reflogs   # no output
git branch -a --contains <commit>     # no output
git show <commit>                     # still shows up

Jeśli to nie jest reflog ani gałąź, ... to musi być tag !

git tag                             # showed several old tags created before the cleanup

git tag -d <tagname>Usunąłem tagi i ponownie uporządkowałem czyszczenie, a stare zatwierdzenia zniknęły.

jakub.g
źródło
Jest już odpowiedź na temat tagów ( stackoverflow.com/a/37335660/450127 ) i nie wygląda na to, żeby dodała coś nowego. Czy nie należy tego usunąć na korzyść wcześniejszej odpowiedzi?
Ian Dunn
Rzeczywiście, jakoś przeoczyłem tę odpowiedź. Chociaż 4 osoby uznały moją odpowiedź za pomocną, więc może nie jest ona taka bezużyteczna? Również zgrupowałem wszystkie możliwości w jedną zwięzłą odpowiedź.
jakub.g
1
Nawet jeśli zostanie zduplikowana, ta strona może pojawić się w wynikach Google i natychmiast pomaga ludziom z tym samym problemem, lepiej niż tylko przekierowywanie ludzi w kółko do linków, które mogą mieć poprawną odpowiedź.
Alexandre T.
14
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

prawdopodobnie po prostu musi być

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

raportować również o oddziałach z pilotów

sehe
źródło
dzięki, teraz znalazłem moje piloty / pochodzenie / następny, który nadal posiada to zatwierdzenie. jak to usunąć? git push -d origin nextnie pomaga.
iRaS
dzięki - git fetch --prunezałatwił sprawę. ale we wszystkich odpowiedziach brakuje mi sprawdzania tagów, które odwołują się do tego zatwierdzenia. Nadal nie wiem, jak sprawdzić tagi z zatwierdzeniem (usunąłem wszystkie).
iRaS
Ale ... czy to oznacza, że ​​zatwierdzenia, które są osiągalne tylko ze zdalnych oddziałów (a żadnych oddziałów lokalnych), są uważane za osiągalne, a zatem git fsck --unreachablefaktycznie komunikują się przez sieć ze zdalnym, aby dowiedzieć się, które zatwierdzenia są osiągalne?
LarsH
1
Odpowiedziałem na moje własne pytanie ... tak, zatwierdzenia, które są osiągalne tylko z odległych oddziałów (i żadnych lokalnych) są uważane za osiągalne; ale git fsck --unreachablenie musi komunikować się przez sieć ze zdalnym, aby dowiedzieć się, które gałęzie zdalne zawierają które zatwierdzenia. Informacje o zdalnym oddziale są przechowywane lokalnie, pod np. .git/refs/remotes/origin(Lub w packed-refs).
LarsH
8

Miałem podobny problem. Pobiegłem git branch --contains <commit>i nie zwróciło żadnego wyniku, tak jak w pytaniu.

Ale nawet po biegu

git reflog expire --expire-unreachable=now --all
git gc --prune=now

mój commit był nadal dostępny przy użyciu git show <commit>. Było tak, ponieważ jeden z zatwierdzeń w jego odłączonej / wiszącej „gałęzi” został oznaczony. Usunąłem tag, ponownie uruchomiłem powyższe polecenia i byłem złoty. git show <commit>wróciłem fatal: bad object <commit>- dokładnie to, czego potrzebowałem. Mam nadzieję, że pomoże to komuś, kto utknął tak samo jak ja.

Andrew Larsson
źródło
jak usunąłeś tag?
bapor
@bapors Wypisz wszystkie znaczniki, znajdź ten, który odwołuje się do danego zatwierdzenia, a następnie usuń go. stackoverflow.com/questions/5480258/…
Andrew Larsson
4

Przypadkowo trafiłem na tę samą sytuację i odkryłem, że moje skrytki zawierają odniesienie do nieosiągalnego zatwierdzenia, a zatem domniemane nieosiągalne zatwierdzenie było osiągalne ze skrytek.

To właśnie zrobiłem, aby uczynić go naprawdę nieosiągalnym.

git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now
Lei Zhao
źródło
2

git gc --prune=<date>domyślnie przycina obiekty starsze niż dwa tygodnie temu. Możesz ustawić późniejszą datę. Jednak polecenia git, które tworzą luźne obiekty, generalnie będą uruchamiać git gc --auto (który czyści luźne obiekty, jeśli ich liczba przekracza wartość zmiennej konfiguracyjnej gc.auto).

Czy na pewno chcesz usunąć te zatwierdzenia? Domyślne ustawienie gc.auto zapewnia, że ​​luźne obiekty nie zajmują zbyt dużej ilości pamięci, a przechowywanie luźnych obiektów przez pewien czas jest ogólnie dobrym pomysłem. W ten sposób, jeśli jutro zdasz sobie sprawę, że usunięta gałąź zawierała zatwierdzenie, którego potrzebujesz, możesz je odzyskać.

dublev
źródło