Przydatne komendy gita
Powiedzmy wprost: git, czyli system kontroli wersji, będący obecnie standardem w branży IT, do intuicyjnych narzędzi nie należy. Fakt, że kiedy zrozumiemy już podstawowe koncepcje i prawa rządzące światem gita, praca z nim staje się szybka i niezwykle efektywna. Niestety krzywą uczenia git ma dość stromą i nawet doświadczonemu użytkownikowi zdarza się czasem jedną źle sformułowaną komendą tak namieszać w naszym repozytorium, że wszechobecne spoty gałęzi gita stają się splotami Czerwia Pustyni, a my czujemy się jak Atrydzi na Diunie - bez nadziei na ratunek ;)
W tej serii artykułów pokażę Wam kilka komend mocy gita, które pozwolą Wam poczuć się jak mistrz Jedi i przywrócić porządek w Galaktyce (repozytorium). Dowiecie się jak bez ryzyka podróżować po splotach branchy gita, jak wytropić zaginione zmiany i jak szybko odnaleźć commit, który wprowadził zamieszanie w repozytorium. Do dzieła!
Na start
Pierwszą komendą, którą chcę opisać jest git stash
, czyli schowek. Bardzo często używam go podczas pracy, ponieważ pozwala na szybkie zapisywanie zmian w podręcznym „schowku”, który nie zmienia struktury repozytorium i zaaplikowanie ich na dowolnym commicie.
Czym jest stash?
Czym zatem jest git stash
?
Jest to mechanizm, który umożliwia zapisanie zmian w lokalnym repozytorium i jednoczesne przywrócenie stanu working directory do stanu określonego przez wskaźnik HEAD. Zapisane zmiany trafiają do „stash” czyli „schowka”, skąd będą mogły być później odzyskane. Schowek jest mechanizmem niezależnym od commitów i loga, świetnie nadaje się zatem do przechowywania zmian stanowiących Work-in-progress, gdyż nie jest uwzględniany w historii commitów i nie zostaje wypchnięty do zdalnego repozytorium.
Aby skorzystać ze schowka, wystarczy utworzyć nowy plik, lub dokonać zmian w istniejącym i wywołać polecenie git stash
:
Komenda git stash zwróci nam następujące informacje:
1. informacje o zapisaniu working directory,
2. informacje o zapisaniu stanu indexu,
3. nazwę brancha i hash commita, na które wskazuje HEAD w momencie utworzenia wpisu w schowku, czyli potocznie tzw. ,,stasha”. Tutaj uwaga: ,,stash” jest zarówno poleceniem, mechanizmem wewnątrz gita, który służy do zapisywania podręcznych zmian (bez zaburzania historii commitów), jak również potocznym określeniem pojedynczego zapisu, znajdującego się w schowku. Ale do tego, co wymienione powyżej informacje oznaczają jeszcze wrócimy.
Domyślnie git stash
zapisuje zmiany, które zostały wcześniej dodane do indexu. Możemy to zmienić dodając flagę -u
lub —include-untracked
. Trzeba jeszcze dodać, że schowek działa na zasadzie LIFO (last-in-first-out), co oznacza, że ostatni dodany element będzie pierwszym, który otrzymamy z powrotem. Domyślnym formatem wiadomości w poleceniu git stash jest „WIP on {branch-name}: {commit-sha-1-hash} {commit-message}
”, ale możemy dodać własną wiadomość za pomocą flagi -m
lub —messsage
. Dobrze jest dodawać takie opisowe wiadomości, ponieważ przy dużej ilości wpisów w ,,stashu”, domyślne wiadomości nie są zbyt pomocne podczas identyfikacji poszczególnych ,,stashy”.
Domyślnie komenda git stash
dodaje do schowka tylko zmiany ze śledzonych plików. Jeśli skorzystamy z flagi -u
,to w ,,stashu” znajdą się również zmiany z nieśledzonych plików. Jeśli chcemy dodać do slasha tylko zmodyfikowane pliki, nieznajdujące się w indeksie, to skorzystamy z flagi —keep-index
lub -k
.
Wyświetlanie listy
Aby sprawdzić, jakie wpisy znajdują się w „stashu”, trzeba użyć komendy git stash list
. Dokładniejszą informację o zmianach zawartych w danym wpisie uzyskamy za pomocą komedy git stash show stash{numer-wpisu}
.
Jeśli chcemy zobaczyć jakie zmiany wprowadza dany wpis, skorzystajmy z flagi -p
lub —pretty
.
Aktywacja zmian
Teraz, kiedy wiemy już jak umieścić nasze zmiany w schowku i zobaczyć, co się w nim znajduje, czas wydobyć nasze zmiany i zaaplikować w naszym working directory. Możemy to zrobić na dwa sposoby.
Po pierwsze możemy skorzystać z komendy git stash apply
(podając opcjonalnie numer wpisu ze schowka stash@{numer-stasha}
). Wtedy zmiany z naszego schowka zostaną dodane do working directory i jednocześnie będą dalej przechowywane w schowku.
Po drugie możemy skorzystać z git stash pop. Wtedy zmiany zostaną dodane do working directory i jednocześnie ucięte ze schowka.
Czyszczenie stasha
Kiedy stash nie jest już potrzebny, możemy wyczyścić jego zawartość. Służą do tego polecenia clear
i drop
. Za pomocą drop możemy usunąć wybrany wpis, podając jego numer. Jeśli nie podamy żadnego numeru, usuniemy ostatni wpis.
Polecenie clear
usuwa wszystkie zmiany zapisane w stashu.
Utworzenie nowego brancha ze stasha
Może się zdarzyć, że będziemy chcieli utworzyć nowy branch dla zmian, które mamy zapisane w stashu. Służy do tego polecenie git stash branch <nazwa-nowego-brancha stash_id>
. Git utworzy wtedy nowego brancha na commicie, z którego utworzyliśmy stash, usunie zmiany ze stasha i doda je do working directory.
Tworzenie stasha bez zmian w reflogu
Git przechowuje ostatni utworzony stash w folderze .git/refs/stash
, pozostałe „stashe” znajdują się w reflogu dla referencji ‚stash’. Czasem może się zdarzyć, że będziemy chcieli utworzyć stash bez zmieniania reflogu. Wtedy możemy skorzystać z polecenia git stash create
. Utworzy ono stash i zwróci jego sha-1 hash, bez dodawania go do reflogu stasha.
Później będziemy mogli dodać ten obiekt do reflogu stasha za pomocą polecenia git stash store <sha-1-hash>
.
W jaki sposób git zachowuje zmiany w stashu?
Kiedy wywołujemy polecenie git stash
, git tworzy obiekt typu commit w folderze .git/refs/stash
.
Ten commit przechowuje stan working directory.
Kiedy podejrzymy go poleceniem git cat-file -p
, zobaczymy, ze ten commit ma dwóch rodziców! Pierwszym jest commit, na którym znajdował się wskaźnik HEAD w momencie wywołania polecania stash. Drugi przechowuje stan indexu w tym momencie.
Ostatni utworzony wpis w stashu jest przechowywany w folderze refs/stash
. Starsze schowki znajdują się w reflogu.
Kiedy zatem używać stasha?
- Kiedy pracujemy nad zadaniem i nagle musimy wykonać hot-fixa o najwyższym priorytecie. Nasze obecne zmiany są jeszcze niegotowe, więc nie będziemy ich commitować, dlatego zachowamy je w stashu. Możemy teraz przenieść się na dowolnego brancha, dokonać niezbędnych poprawek, po czym wrócić do przerwanej pracy.
- Może zdarzyć się, że w ferworze walki z jakimś wyjątkowo złośliwym bugiem nie zorientujemy się, że pracujemy na niewłaściwym branchu. Manualne kopiowanie zmian nie jest na szczęście konieczne, wystarczy zachować zmiany w stashu i zaaplikować na właściwym branchu.
- Kiedy jesteśmy w trakcie pracy nad zmianą i nagle dowiadujemy się, że w zdalnym repozytorium zaszły zmiany, które musimy włączyć do naszej pracy. Git pull odmawia nadpisania naszych zmian - wystarczy schować zmiany w stashu, wykonać git pull, a następnie odzyskać zmiany ze schowka
Mam nadzieję, że ta użyteczna komenda pomoże Wam pokonać lęk przed utraceniem zmian, kiedy przełączacie się między branchami. Być może poprawi Waszą swobodę w pracy z gitem i przybliży Was do gitowego „mistrzostwa” :) Ja osobiście korzystam ze stasha bardzo często, zwłaszcza kiedy otrzymuję dużo „wrzutek”, a jednocześnie muszę pracować nad bieżącymi zadaniami.