Git stash – Staszek to świetny kumpel

skrzynia ze skarbami

Wprowadzenie do mechanizmu schowka

Ci, którzy mnie znają, wiedzą że jestem fanem gita. Pokochałem to narzędzie już na samym początku jego użytkowania. Nauczyłem się kilku podstawowych komend i myślałem, że już nigdy mnie nie zaskoczy. Dopóki pracowałem sam nad jednym projektem…

Pamiętam dokładnie moment, w którym pierwszy raz użyłem stasha. Pracowałem nad jakąś funkcjonalnością i kolega poprosił mnie, żebym bezzwłocznie zrobił dla niego jedną poprawkę. Kiedy odpowiedziałem, że najpierw muszę dokończyć pracę nad tym featurem, bo nie chcę commitować niedziałającego kodu, usłyszałem: git stash. Wrzuciłem frazę w wyszukiwarkę i poczytałem. Od tego czasu na dobre zakumplowałem się z Git Stanisławem (chyba w tym momencie wymyśliłem tę nazwę) i dzisiaj nie wyobrażam sobie pracy bez niego.

Czym właściwie jest schowek gita? To mechanizm pozwalający zapisać zmiany w lokalnym repozytorium. Jest zupełnie odseparowany od commitów i loga. Nie ma możliwości wypchnięcia go do zdalnego repo. Kod, który trafia do stasha raczej nie zagości tam na długo.

Schowek jest zaimplementowany jako stos. Wszystkie poniższe polecenia podane bez indeksu stash@{1} działają dla ostatniego odłożonego elementu, czyli w praktyce tego z indeksem 0. Dorzucam jeszcze link do dokumentacji i nie przedłużając – przechodzę do konkretów.

Git stash – opis komend

Nie wiem jak z obsługą tego mechanizmu w graficznych interfejsach gita. Nie korzystałem z nich nigdy i zawsze polecam używać terminala. Na szybko sprawdziłem tylko w PhpStormie, że jest do dyspozycji okrojona wersja stasha.

Wyświetlanie listy

W celu sprawdzenia jakie stashe istnieją, należy użyć poniższej komendy. Zaprezentowany został także przykładowy rezultat polecenia. Jak widać, prosta lista zawiera informacje o indeksie schowka, jego opis i gałąź na której został stworzony.

git stash list
text on gray background

Chowanie zmian

Odłożenie zmian na stos schowka realizuje się za pomocą poniższego polecenia. Istnieje także alternatywa, zawierająca frazę save zamiast push. W zasadzie to save był pierwszy, ale w wersji 2.15 został oznaczony jako depracated, a docelowo ma zostać usunięty. Więcej na ten temat możecie poczytać tutaj.

Z poziomu użytkownika nie ma żadnych różnic, dlatego od razu lepiej przyzwyczaić się do tej nowszej. Wspominam jednak o tym, dlatego że nie wszyscy korzystają z najnowszych wersji gita. Oczywiście polecam sobie zaktualizować, gdyż po drodze były też łatane dziury bezpieczeństwa.

git stash push

Chowanie zmian ma zdecydowanie najwięcej możliwych opcji. Jedną z nich jest flaga -m, która pozwoli dodać opis, tak jak widać na zamieszczonym zrzucie z przykładowej listy. Ja nauczyłem się dodawać ją zawsze i traktuję ją jako wymaganą. Jeśli z niej nie skorzystacie, to użyty zostanie automatyczny opis, który zawiera informacje o ostatnim commicie z momentu chowania zmian. Zdecydowanie nieczytelne, kiedy istnieje kilka schowków. Nie obejdzie się bez podglądnięcia, jakie zmiany zawierają.

Domyślnie powyższa komenda doda do schowka tylko zmiany ze śledzonych plików, czyli takich, które zostały już kiedykolwiek dodane do indeksu. Aby uwzględnić wszystkie zmienione pliki pomocna okaże się flaga -u. Wykluczenie natomiast tych zmian, które zostały zaindeksowane to opcja -k. Wybranie konkretnych fragmentów kodu mających znaleźć się w schowku umożliwi -p, czyli tryb interaktywny.

Ostatnią opcją, którą tutaj wymienię jest -all. Pozwoli zapisać do schowka wszystkie pliki wykluczone z repozytorium, czyli w praktyce te wylistowane w pliku .gitignore. Mi nie zdarzyło się z niej skorzystać, ale wspominam o niej w ramach ciekawostki – może się przyda.

Podgląd zmian

Tutaj kwestia jest bardzo prosta – pokazanie konkretnych różnic z aktualną wersją. Po wykonaniu polecenia, ujrzeć można widok przypominający output z git diff.

git stash show stash@{1}

Aktywacja zmian

Przywrócenie kodu ze stasha możliwe jest na dwa sposoby. Pierwszy z nich pozwoli aktywować zmiany, ale nie usunie konkretnego schowka. Drugi natomiast jest połączeniem apply i drop. Warto odnotować, że w przypadku konfliktu stash nigdy nie jest usuwany. Analogicznie zresztą jak przy scalaniu gałęzi.

git stash apply stash@{1}
git stash pop stash@{1}

Każda aktywacja zmian całkowicie resetuje stan indeksacji jaki miał miejsce podczas ich zapisywania. W tym momencie we wszystkich edytowanych plikach git rozpoznaje zmiany względem tego co ma w indeksie. Odwzorowanie stanu z momentu stashowania można uzyskać korzystając z dodatkowej opcji –index. Nie zadziała ona jednak przy wystąpieniu konfliktu.

Usuwanie git stashy

Za wyczyszczenie całego stosu odpowiedzialna jest poniższa komenda. Drop natomiast służy do usunięcia konkretnego schowka.

git stash clear
git stash drop stash@{1}

Dodatkowe, mniej przydatne

Dla kompletności tego wpisu dorzucam też 3 dodatkowe polecenia, których ja osobiście nie używam. Pierwsze z nich to połączenie dwóch kroków w jeden. Mowa o utworzeniu gałęzi i aktywację zmian ze schowka.

git stash branch branch_name

Dwa poniższe natomiast to jakby cichy schowek. W dokumentacji znalazłem informacje, że mechanizm ten jest przydatny w skryptach. Obie komendy są używane razem, gdzie pierwsza z nich przygotowuje schowek zwracając ciąg znaków (hash_string), a druga pozwala na jego podstawie odłożyć schowek na stos.

git stash create
git stash store hash_string

Trzy najczęstsze przypadki użycia git stasha

  1. Praca nad długim zadaniem przerwana tak zwaną wrzutką, czyli taskiem z najwyższym priorytetem. Mam nadzieje, że od dzisiaj nikomu z Was nie przyjdzie do głowy świadome commitowanie niedokończonego lub niedziałającego kodu.

2. Niedokończone zadanie, a dzień się skończył? A może kolejne „ważne” spotkanie? Wrócicie do kodu i nie będziecie pamiętać co robiliście. A przecież zawsze można skorzystać z sensownie opisanego stasha.

3. Po długiej walce naprawiliście błąd. Problem w tym, że nie zauważyliście, że pracujecie na złej gałęzi, a zmiany trzeba wgrać na innej. Wierzę, że od dziś już nikt nie pomyśli o manualnym kopiowaniu zmian.

Krystian Żądło
Programista PHP i właściciel marki Koddlo. Pasjonat czystego kodu i dobrych praktyk programowania obiektowego. Prywatnie fan angielskiej piłki nożnej, dobrego humoru oraz podcastów.