Oczyszczanie środowiska Git
Polecenie git prune
jest wewnętrznym narzędziem do konserwacji, które pozwala wyczyścić nieosiągalne lub „osierocone” obiekty Git. Obiektami nieosiągalnymi są te, które nie są dostępne za pośrednictwem żadnych referencji. Nieosiągalny jest każdy commit, do którego nie można uzyskać dostępu za pośrednictwem gałęzi lub tagu. Polecenia git prune
zasadniczo nie wykonuje się bezpośrednio. Polecenie prune jest uznawane za jedno z poleceń przeznaczonych do usuwania niechcianych elementów i jest poleceniem podrzędnym względem polecenia git gc.
Git Prune — przegląd
Aby poznać skutki użycia polecenia git prune
, trzeba przeprowadzić symulację scenariusza, w którym commit staje się nieosiągalny. Poniżej przedstawiono sekwencję wykonań wiersza polecenia, które pozwolą zasymulować tę sytuację.
~ $ cd git-prune-demo/
~/git-prune-demo $ git init .
Initialized empty Git repository in /Users/kev/Dropbox/git-prune-demo/.git/
~/git-prune-demo $ echo "hello git prune" > hello.txt
~/git-prune-demo $ git add hello.txt
~/git-prune-demo $ git commit -am "added hello.txt"
Poprzednia sekwencja poleceń spowoduje utworzenie nowego repozytorium w katalogu o nazwie git-prune-demo
. Do repozytorium dodany zostanie jeden commit składający się z nowego pliku hello.txt
o podstawowej zawartości „hello git prune”. Następnie utworzymy modyfikację pliku hello.txt
, a na jej podstawie także nowy commit.
~/git-prune-demo $ echo "this is second line txt" >> hello.txt
~/git-prune-demo $ cat hello.txt
hello git prune
this is second line txt
~/git-prune-demo $ git commit -am "added another line to hello.txt"
[main 5178bec] added another line to hello.txt
1 file changed, 1 insertion(+)
materiały pokrewne
Jak przenieść pełne repozytorium Git
POZNAJ ROZWIĄZANIE
Poznaj środowisko Git z rozwiązaniem Bitbucket Cloud
W naszym demonstracyjnym repozytorium mamy teraz historię zawierającą 2 commity. Możemy to zweryfikować, używając polecenia git log
:
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 14:49:59 2018 -0700
added another line to hello.txt
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
Wynik uzyskany po wykonaniu polecenia git log będzie wskazywał 2 commity oraz odpowiednie komunikaty commitów dotyczące zmian wprowadzonych w pliku hello.txt
. Kolejnym krokiem w naszym przypadku jest ustawienie jednego z commitów jako nieosiągalnego. Wykorzystamy w tym celu polecenie git reset. Przywrócimy repozytorium do stanu pierwszego commita, czyli „added hello.txt”.
~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt
Jeśli teraz użyjemy pliku git log
do zbadania stanu repozytorium, zobaczymy, że mamy tylko jeden commit.
~/git-prune-demo $ git log
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
Repozytorium demonstracyjne zawiera teraz odłączony commit. Drugi wykonany commit opatrzony komunikatem „added another line to hello.txt” nie jest już wyświetlany w wynikach polecenia git log
i jest teraz odłączony. Może się wydawać, że commit został utracony lub usunięty, ale Git bardzo rygorystycznie traktuje nieusuwanie historii. Możemy potwierdzić, że jest on dostępny, ale odłączony, przechodząc do niego bezpośrednio za pomocą polecenia git checkout
:
~/git-prune-demo $ git checkout 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Note: checking out '5178becc2ca965e1728554ce1cb8de2f2c2370b1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 5178bec... added another line to hello.txt
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 14:49:59 2018 -0700
added another line to hello.txt
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
Jeśli wyewidencjonujemy odłączony commit, Git jest na tyle przemyślany, że zwróci nam szczegółowy komunikat z wyjaśnieniem, że pracujemy w stanie odłączonym. Jeśli przeanalizujemy przedstawiony tutaj dziennik, zauważymy, że commit „added another line to hello.txt” znajduje się z powrotem w wygenerowanym dzienniku. Teraz, gdy wiemy, że repozytorium znajduje się w odpowiednim stanie symulacji z odłączonym commitem, możemy przećwiczyć polecenie git prune
. Jednak najpierw wróćmy do gałęzi main
za pomocą polecenia git checkout
.
~/git-prune-demo $ git checkout main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
5178bec added another line to hello.txt
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> 5178bec
Switched to branch 'main'
Gdy wrócimy do gałęzi main za pomocą polecenia git checkout
, Git po raz kolejny przemyślnie powiadomi nas, że opuszczamy odłączony commit. Przyszedł czas na oczyszczenie odłączonego commita. Teraz wykonamy polecenie git prune
, jednak najpierw musimy przekazać do niego pewne opcje. Opcje --dry-run
i --verbose
spowodują wyświetlenie wyniku ze wskazaniem, co zostanie oczyszczone, bez wykonywania faktycznej operacji oczyszczania.
~/git-prune-demo $ git prune --dry-run --verbose
Polecenie to najprawdopodobniej zwróci pusty wynik. Pusty wynik oznacza, że operacja oczyszczenia nie spowoduje usunięcia niczego. Dlaczego tak się dzieje? Cóż, najprawdopodobniej commit nie został w pełni odłączony. Gdzieś w Git wciąż znajduje się do niego referencja. To doskonały przykład ilustrujący, dlaczego polecenia git prune
nie należy używać niezależnie od polecenia git gc
. Jest to również dobry przykład tego, jak trudno jest całkowicie utracić dane w Git.
Najprawdopodobniej Git przechowuje referencję do naszego odłączonego commita w dzienniku reflog. Możemy to przeanalizować, wykonując polecenie git reflog. Powinien wyświetlić się wynik z opisem sekwencji czynności wykonanych, zanim doszliśmy do tego momentu. Więcej informacji na temat polecenia git reflog
można znaleźć na stronie git reflog. Oprócz zachowania historii w dzienniku reflog, Git ma wewnętrzne daty ważności, zgodnie z którymi odłączone commity są oczyszczane. To wszystko również są szczegóły wdrożeniowe, z którymi radzi sobie git gc
, co potwierdza, że polecenia git prune
nie należy używać niezależnie.
Aby zakończyć naszą demonstrację symulującą działanie polecenia git prune
, musimy wyczyścić dziennik reflog.
~/git-prune-demo $ git reflog expire --expire=now --expire-unreachable=now --all
Powyższe polecenie wymusi wygaśnięcie wszystkich wpisów w dzienniku reflog, które zostały dodane wcześniej niż teraz. Jest to brutalne i niebezpieczne polecenie i na co dzień użytkownik Git nie powinien się znaleźć w sytuacji wymagającej jego użycia. My wykonujemy to polecenie, aby zademonstrować udane wykonanie operacji git prune
. Po całkowitym wyczyszczeniu dziennika reflog możemy wykonać polecenie git prune
.
~/git-prune-demo $ git prune --dry-run --verbose --expire=now
1782293bdfac16b5408420c5cb0c9a22ddbdd985 blob
5178becc2ca965e1728554ce1cb8de2f2c2370b1 commit
a1b3b83440d2aa956ad6482535cbd121510a3280 commit
f91c3433eae245767b9cd5bdb46cd127ed38df26 tree
To polecenie powinno zwrócić listę referencji do obiektów w formie hashy Git podobną do powyższej.
Użycie
Poleceniu git prune
towarzyszy krótka lista opcji omówionych w sekcji przeglądu.
-n --dry-run
Nie wykonuj operacji oczyszczania. Po prostu wyświetl wynik, który uzyskamy w przypadku jej wykonania.
-v --verbose
Wyświetl dane wyjściowe wszystkich obiektów i działań uwzględnionych w operacji oczyszczania.
--progress
Wyświetla wynik wskazujący postęp operacji oczyszczania.
--expire <time>
Wymuś wygaśnięcie obiektów, które są wcześniejsze niż
<head>…
Zdefiniowanie parametru spowoduje zachowanie wszelkich opcji z tej referencji head.
Dyskusja
Czym różnią się od siebie polecenia git prune, git fetch --prune oraz git remote prune?
Polecenia git remote prune
i git fetch --prune
pełnią taką samą funkcję: usuwają referencje do gałęzi nieistniejących w repozytorium zdalnym. Jest to wysoce pożądane podczas pracy w ramach zespołowego przepływu pracy, w którym gałęzie zdalne są usuwane po scaleniu z gałęzią main
. Drugie polecenie — git fetch --prune
— spowoduje połączenie z repozytorium zdalnym i pobranie najnowszego stanu gałęzi zdalnej przed wykonaniem oczyszczania. Jest to zasadniczo kombinacja następujących poleceń:
git fetch --all && git remote prune
Ogólne polecenie git prune
jest całkowicie inne. Jak omówiono w sekcji przeglądu, polecenie git prune powoduje usunięcie lokalnie odłączonych commitów.
Jak oczyszczać nieaktualne gałęzie?
Polecenie git fetch --prune
jest najlepszym narzędziem do oczyszczania nieaktualnych gałęzi. Nawiązuje ono połączenie ze współdzielonym zdalnym repozytorium i pobiera wszystkie referencje gałęzi zdalnych. Następnie usuwa referencje gałęzi zdalnych, które już nie są używane w repozytorium zdalnym.
Czy polecenie git remote prune origin usuwa gałąź lokalną?
Nie, polecenie git remote prune origin
spowoduje jedynie usunięcie referencji do gałęzi zdalnych, które już nie istnieją. W Git przechowywane są zarówno referencje lokalne, jak i zdalne. Repozytorium będzie zawierało zbiór referencji local/origin
i remote/origin
. Polecenie git remote prune origin
spowoduje oczyszczenie referencji jedynie w zbiorze remote/origin
. Praca lokalna pozostanie bezpieczna w zbiorze local/origin
.
Git Prune — podsumowanie
Polecenie git prune
wywoływane jest jako polecenie podrzędne względem polecenia git gc
. W trakcie codziennych prac programistycznych konieczność wywołania polecenia git prune
jest mało prawdopodobna. Do zrozumienia skutków działania polecenia git prune
konieczne jest odwołanie się do innych poleceń. W tym artykule użyliśmy między innymi takich poleceń, jak git log
, git reflog
i git checkout
.
Udostępnij ten artykuł
Następny temat
Zalecane lektury
Dodaj te zasoby do zakładek, aby dowiedzieć się więcej na temat rodzajów zespołów DevOps lub otrzymywać aktualności na temat metodyki DevOps w Atlassian.