Czy usunięcie oddziału w git usuwa go z historii?

190

Pochodzący z svn, dopiero zaczynam się zapoznawać z git.

Czy gałąź usuwana w git jest usuwana z historii?

W svn możesz łatwo odzyskać gałąź, cofając operację usuwania (scalanie odwrócone). Podobnie jak wszystkie usunięcia w svn, gałąź tak naprawdę nigdy nie jest usuwana, po prostu jest usuwana z bieżącego drzewa.

Jeśli gałąź faktycznie zostanie usunięta z historii w git, co stanie się ze zmianami, które zostały scalone z tej gałęzi? Czy są zatrzymane?

Ken Liu
źródło

Odpowiedzi:

251

Gałęzie są tylko wskazówkami do zatwierdzenia w git. W git każde zatwierdzenie ma pełne drzewo źródłowe, jest to zupełnie inna struktura niż svn, w której wszystkie gałęzie i znaczniki (zgodnie z konwencją) żyją w osobnych „folderach” repozytorium obok specjalnego „trunk”.

Jeśli gałąź została połączona z inną gałęzią przed jej usunięciem, wszystkie zatwierdzenia będą nadal dostępne z drugiej gałęzi po usunięciu pierwszej gałęzi. Pozostają dokładnie takie, jakie były.

Jeśli gałąź zostanie usunięta bez połączenia z inną gałęzią, zatwierdzenia w tej gałęzi (aż do momentu, w którym rozwidlenie od zatwierdzenia, które jest nadal osiągalne) przestanie być widoczne.

Zatwierdzenia będą nadal przechowywane w repozytorium i można je odzyskać natychmiast po usunięciu, ale ostatecznie zostaną one wyrzucone.

CB Bailey
źródło
3
Dziękuję za odpowiedź. Czy możesz wyjaśnić, co rozumiesz przez „każde zatwierdzenie ma pełne drzewo źródeł”? Jak rozumiem, każde zatwierdzenie w git jest zbiorem delt, które odwołują się do zatwierdzenia nadrzędnego, a nie całego drzewa.
Ken Liu,
2
@Ken Liu: Zatwierdzenie zawiera wskaźniki do zerowego lub więcej zatwierdzeń nadrzędnych, obiekt drzewa i niektóre metadane dotyczące zatwierdzenia. Zatwierdzenie jednoznacznie identyfikuje zatem zarówno drzewo źródeł pary, jak i, w porównaniu z rodzicami, zmiany, które wprowadził.
CB Bailey,
9
@Ken Liu: To zależy dokładnie od tego, czym byłeś przez „zawierać”, ale tak, zasadniczo każde zatwierdzenie zawiera pełne drzewo. W bazie danych obiektów obiekty są indeksowane według identyfikatora, więc obiekty są współużytkowane między wszystkimi obiektami (drzewami i zatwierdzeniami), które się do nich odwołują, więc domyślny narzut pamięci nie jest tak zły, jak się początkowo wydaje. git ma również wydajną optymalizację pamięci (pliki paczek), która jeszcze bardziej efektywnie wykorzystuje miejsce na dysku.
CB Bailey,
22
„w końcu będą zbierane śmieci” - w końcu kiedy?
BadHorsie
7
@BadHorsie, to zależy .
AliOli,
86

W Git gałęzie są tylko wskaźnikami (referencjami) zatwierdzeń na ukierunkowanym wykresie acyklicznym (DAG) zatwierdzeń. Oznacza to, że usunięcie gałęzi usuwa tylko odwołania do zatwierdzeń, co może sprawić, że niektóre zatwierdzenia w DAG będą nieosiągalne, a tym samym niewidoczne. Ale wszystkie zatwierdzenia, które znajdowały się w usuniętej gałęzi, nadal znajdowałyby się w repozytorium, przynajmniej do momentu przycięcia nieosiągalnych zatwierdzeń (np. Za pomocą git gc).

Zauważ, git branch -dże odmówiłoby usunięcia gałęzi, jeśli nie ma pewności, że usunięcie go nie pozostawi nieosiągalnych zatwierdzeń. Musisz użyć silniejszego, git branch -Daby wymusić usunięcie gałęzi, jeśli może pozostawić nieosiągalne zatwierdzenia.

Zauważ też, że nieosiągalne zatwierdzenia, jeśli są obecne, są tylko zatwierdzeniami między ostatnią końcówką usuniętej gałęzi a albo zatwierdzeniem, które zostało scalone z innym istniejącym oddziałem, dowolnym oznaczonym zatwierdzeniem lub punktem rozgałęzienia; cokolwiek jest później. Na przykład w następującej sytuacji:

---- O ---- * ---- * ---- / M ---- * <- master <- HEAD
     \ /
      \ --. ---- .-- / - x --- y <- usunięty oddział

tylko zatwierdzenia „x” i „y” stałyby się nieosiągalne po usunięciu gałęzi.

Jeśli działałeś na usuniętym oddziale w tym gc.reflogExpireokresie, domyślnie 90 dni, ostatnia wskazówka usuniętego oddziału zostanie zapisana w dzienniku HEAD (patrz git reflog show HEADlub git log --oneline --walk-reflogs HEAD). Powinieneś być w stanie użyć HEAD reflog do odzyskania usuniętego wskaźnika. Należy również pamiętać, że w tym przypadku nieosiągalne zatwierdzenia w tylko usuniętej gałęzi byłyby chronione przed przycinaniem (usuwaniem) w gc.reflogExpireUnreachableokresie, który domyślnie wynosi 30 dni.

Jeśli nie możesz znaleźć końcówki właśnie usuniętej gałęzi w reflog dla HEAD, możesz spróbować użyć git fsck„nieosiągalnego zatwierdzenia <sha1>” i zbadać te (przez git show <sha1>lub git log <sha1>), aby znaleźć końcówkę usuniętej gałęzi.

Niezależnie od tego, jak znaleźć końcówkę usuniętej gałęzi, możesz cofnąć usunięcie, a raczej odtworzyć właśnie usuniętą gałąź za pomocą

git branch <deleted-branch> <found-sha1-id>

Należy jednak pamiętać, że dziennik logowania dla gałęzi zostałby utracony.


Istnieje również skrypt git-resurrect.sh, w contrib/którym pomaga znaleźć ślady wierzchołka gałęzi o podanej nazwie i wskrzesić (cofnąć).

Jakub Narębski
źródło
1
Niesamowite! git reflog show HEADwymieniłem zatwierdzenie i stworzyłem nowy oddział, tak jak powiedziałeś, idealnie.
Steven Almeroth
2

Jeśli martwisz się przypadkowo usuniętymi gałęziami i nie masz już lokalnej kopii repozytorium, istnieją rozszerzenia do korporacyjnych serwerów Git, takich jak Gerrit, które wykrywają przepisywanie historii i usuwanie gałęzi, wykonują kopie zapasowe pod specjalnym ref, aby mogły może zostać przywrócony w razie potrzeby i nie będzie przycinany przez zbieranie śmieci. Administratorzy Gerrit mogą nadal usuwać wybrane zatwierdzenia, jeśli jest to konieczne ze względów prawnych.

Johanned Nicolai
źródło