Close

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(+)
Bazy danych
materiały pokrewne

Jak przenieść pełne repozytorium Git

Logo Bitbucket
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.

Ludzie współpracujący przy ścianie pełnej narzędzi

Blog Bitbucket

Ilustracja DevOps

Ścieżka szkoleniowa DevOps

Demonstracje funkcji z ekspertami Atlassian

Zobacz, jak Bitbucket Cloud współpracuje z Atlassian Open DevOps

Zapisz się do newslettera DevOps

Thank you for signing up