Git – poradnik początkującego, strona 2

Podstawy Gita dla początkujących użytkowników. Jeśli znasz SVN-a i zaczynasz pracę z Gitem, to właśnie coś dla Ciebie. Jeśli nie znasz SVN, to chyba nawet lepiej – unikniesz problemów z zastanawianiem się dlaczego Git działa inaczej.

Spis treści

  1. Kilka słów wstępu o Git (strona 1)
  2. Dlaczego Git jest lepszy od SVN? (strona 1)
  3. Pierwsze kroki z Gitem (strona 1)
  4. Zatwierdzanie zmian (strona 1)
  5. Synchronizacja z repozytorium zdalnym (strona 1)
  6. Praca z gałęziami (branch)
  7. Naprawianie błędów w obsłudze Gita, czyli tzw. undo
  8. Obsługa SVN-a przy pomocy Gita
  9. Kilka przydatnych informacji na koniec

Praca z gałęziami (branch)

Przy małych projektach, lub przy projektach nad którymi pracuje jedna osoba, gałęzie mogą być mniej przydatne (chociaż przy nieliniowym rozwijaniu funkcjonalności należy z nich korzystać). Jednak przy większych projektach, nad którymi pracuje często wiele osób, gałęzie są podstawą wygodnej pracy.

Gałąź (branch) to nic innego, jak kopia pewnej wersji (w zasadzie konkretnego commita), która jest rozwijana niezależnie od gałęzi z której powstała (np. gałęzi master). Dzięki temu, można różne funkcjonalności rozwijać na osobnych gałęziach, a w momencie gdy zostaną skończone – zcalić je (zmerge’ować) do gałęzi z której powstały.

Tworzenie nowych gałęzi

Zakładając że pracujesz na gałęzi master i chcesz stworzyć nową gałąź z funkcjonalnością X, wykonaj polecenie git checkout -b featureX. Powoduje to stworzenie nowej gałęzi o nazwie featureX i przełączenie na nią. Każdy commit który wykonasz, będzie dotyczył gałęzi featureX a nie gałęzi master, jak do tej pory. Możesz w niej dodawać pliki, modyfikować czy usuwać. Oczywiście zwykle taką gałąź należy zsynchronizować z repozytorium głównym przez git push.

Jak zakończysz pracę w gałęzi, zapewne będziesz chciał zrobić merge nowych funkcjonalności (lub np. bugfiksa) do gałęzi głównej. Przełącz się zatem na gałąź master: git checkout master (w ten sposób przełączasz się pomiędzy gałęziami, oczywiście możesz tworzyć ich wiele). Wszystkie pliki i katalogi projektu automatycznie zostały zaktualizowane do wersji znajdującej się w tej gałęzi. Teraz, należy wykonać polecenie git merge featureX, a po nim zwykle git push. Gałęzi takich raczej nie należy pozostawiać, skoro nic nie wnoszą do projektu – pełna historia zmian z gałęzi featureX została również uwzględniona w gałęzi master.

Git-flow jako sposób wygodnej pracy

Przy dużych projektach warto się zaznajomić z często wykorzystywanym git-flow. Jest to wygodny sposób na utrzymanie wersji produkcyjnej (gałąź master), integracyjnej (gałąź develop) oraz osobnych gałęzi dla bugów, fiksów i rozwijanych nowych funkcjonalności. Więcej informacji na temat git-flow znajdziesz np. na stronie Atlassiana.

Naprawianie błędów w obsłudze Gita, czyli tzw. undo

Przywrócenie wersji z ostatniego commita

Jeśli w trakcie zmian (zanim zrobisz git commit) stwierdzisz, że jednak nie prowadzą do niczego dobrego, możesz łatwo przywrócić wersję z ostatniego commita. Jeśli chcesz przywrócić pojedynczy plik, użyj polecenia git checkout -- <plik>. Ten plik zostanie przywrócony, pozostałe nie będą zmodyfikowane. Jeśli natomiast chcesz przywrócić cały projekt do wersji z ostatniego commita, należy wykonać git reset --hard HEAD. Używaj obu opcji z głową, ponieważ nie będziesz w stanie tych poleceń wycofać.

Poprawienie ostatniego commita

Jedną z ciekawych możliwości Gita jest poprawienie ostatniego (i tylko ostatniego) commita. Możesz w ten sposób zmienić jego opis (bo np. po fakcie zorientowałeś się że wkradła się literówka, czy zapomniałeś dołączyć nowy plik, a commit wykonałeś tradycyjnie przez git commit -a -m"Jakiś komunikat"). Jeśli zapomniałeś o pliku, dodaj go teraz przez git add <nowy plik>. Następnie wykonaj aktualizację ostatniego commita (zostanie on zastąpiony) przez git commit --amend -m"Jakiś komunikat oraz nowy plik". Dla bezpieczeństwa innych ludzi pracujących przy projekcie, nie poprawiaj nigdy commitów które zsynchronizowałeś do zdalnego repozytorium przez git push.

Jeśli jakieś zmiany zacommitowałeś lokalnie, ale jeszcze nie wypchałeś (push) do zdalnego repozytorium, możesz je wycofać. Oczywiście nie chodzi mi o usunięcie całego katalogu z projektem i ponowne zrobienie git clone,choć to oczywiście również zadziała :)

Powrót do jednego z wcześniejszych commitów

Oczywiście może się zdarzyć i tak, że z jakichś względów zacommitowałeś coś, czego obecnie nie chcesz. Możesz powrócić do jednego z wczesniejszych commitów na dwa sposoby. Po pierwsze, sprawdź poleceniem git log -5 ostatnie 5 commitów (oczywiście możesz dać inny limit niż 5). Przy każdym commicie masz jego identyfikator, np. commit 252bf50d1f4edc210a5e81190d891d4128712aeb. Możesz teraz wycofać zmiany wprowadzone pomiędzy wspomnianym commitem 252bf50d1f4edc210a5e81190d891d4128712aeb a wersją aktualną, poleceniem git revert 252bf50d1f4edc210a5e81190d891d4128712aeb. W historii zmian w Twoim projekcie zostanie dodana informacja o wycofaniu, a wersje pośrednie (wszystkie pomiędzy commitem 252bf50d1f4edc210a5e81190d891d4128712aeb a obecnym, który wycofujesz), zostaną zachowane w historii i będziesz mógł do nich wrócić, jeśli okaże się że wycofanie nie było dobrym pomysłem.

Drugą opcją jest wycofanie (załóżmy że ponownie do commita 252bf50d1f4edc210a5e81190d891d4128712aeb) przez opcję git reset --hard 252bf50d1f4edc210a5e81190d891d4128712aeb (podobne do powyższego wycofania zmian lokalnych, których nie commitowałeś). Różni się tym, że historia modyfikacji pomiędzy commitem 252bf50d1f4edc210a5e81190d891d4128712aeb a wersją obecną zostanie również „wycofana” (m.in. git log jej nie pokaże). Przez jakiś czas będziesz miał jeszcze szansę na dobranie się do wersji pomiędzy 252bf50d1f4edc210a5e81190d891d4128712aeb a obecną (sprzed wykonania resetu), jednak wymaga to informacji dość dogłębnych m.in. o sposobie działania Gita i nie jest to temat na ten poradnik. Dodatkowo, w zależności od konfiguracji Gita, po czasie kilku do kilkudziesięciu dni, dane zostaną utracone bezpowrotnie. Zatem prawdopodobnie nie jest to opcja którą chcesz użyć, chyba że np. dodałeś przez pomyłkę w commicie do projektu jakieś pliki nie związane z projektem.

Obsługa SVN-a przy pomocy Gita

Tak, jest taka opcja, choć ma wiele minusów. Osobiście wolę używać Gita tam gdzie mam repozytorium Gitowe, a klienta SVN tam gdzie mam repozytorium SVN. Jednak do rzeczy.

Aby rozpocząć, musisz „sklonować” repozytorium SVN przez git svn clone <adres-do-repozytorium-svn>. Zwróć uwagę na początek polecenia – wszystkie polecenia w przypadku repozytorium SVN zaczynają się od git svn. Jak to ma w zwyczaju Git, zostanie zaciągnięty cały projekt, czyli również z tagami i branchami, oraz całą historią. Jeśli projekt ma sporą historię, albo wiele branchy (gałęzi) i tagów, może to potrwać dość długo. Opcją alternatywną jest zainicjowanie repozytorium przez git svn init <adres-do-repozytorium-svn>, a następnie zaciągnięcie jedynie najnowszej rewizji projektu bez jego długiej historii, przez git svn fetch -r HEAD. Pełne opcje do polecenia svn init oraz svn fetch znajdziesz w dokumentacji online, lub przez man svn-git. Aktualizacja projektu (czyli coś analogicznego do svn update) to polecenie git svn rebase, a wykonanie commita to git svn dcommit (coś jak svn commit, a ta literk d to nie błąd).

Oczywiście, możesz używać lokalnie git commit, co tak jak zwykle nie będzie miało żadnego efektu na repozytorium zdalnym. Będziesz jednak w stanie poruszać się po lokalnych commitach, korzystać z nich, przywracać pliki do tych wersji itd. Tego klient SVN nie daje.

Teoretycznie możesz używać wielu poleceń Gita, aby tworzyć branche, robić merge itp., ale ze względu na fakt że ani svn:mergeinfo, ani opcja reintegrate przy merge nie działa, dla mnie narzędzie staje się bezużyteczne. Jeśli korzystasz z własnego repozytorium, możesz w nim robić co chcesz. Ale jeśli chcesz korzystać z tego narzędzia np. w firmie, możesz więcej napsuć innym (i sobie) niż zyskać.

Jako że wszystkie atrybuty poza svn:executable są ignorowane, nie będziesz w stanie używać np. svn:externals czy svn:ignore – kolejny minus.

Kilka przydatnych informacji na koniec

Przyjemniejsza praca w konsoli

Aby w konsoli praca z Gitem była przyjemniejsza, można zrobić dwie rzeczy o których wcześniej nie wspominałem. Po pierwsze, dopełnianie składni poleceń analogicznie jak to działa z dopełnianiem nazw poleceń systemowych, czy nazw plików. Ściągnij plik completion/git-completion.bash do swojego katalogu domowego (np. do ~/git-completion.bash) i w pliku ~/.bashrc dopisz:

source ~/git-completion.bash

Po przelogowaniu możesz używać tabulatora do dopełniania poleceń czy nazw branchy.

Druga rzecz, to kolorowanie wybranych części komunikatów. Aby je włączyć, wykonaj polecenie

git config --global color.ui auto

Dzięki temu np. git status zaznaczy kolorem informacje o zmienionych czy dodanych plikach. Na pierwszy rzut oka będzie widać, jakie zmiany będą commitowane.

Klient okienkowy

Oczywiście dla wielu użytkowników wygodniejsze od konsoli są okienka. Jeśli korzystałeś już z TortoiseSVN, zapewne przypadnie Ci do gustu TortoiseGit – podobny interfejs, podobna integracja z systemem.

Jeśli korzystasz z GitHuba, być może wygodniejszym będzie klient dedykowany jemu klient, do ściągnięcia na jednej z podstron GitHuba.

Więcej opcji znajdziesz na stronie git-scm.com/downloads/guis, również dla Maca i Linuksa. Jednak niezależnie od klienta okienkowego który wiele rzeczy może ułatwić, podstawy które się wiążą z konkretnymi poleceniami konsolowymi (m.in. opisanymi wcześniej przeze mnie) musisz poznać.

Dokumentacja

Oczywiście tak krótki poradnik jak ten, nie jest w stanie dostarczyć pełnej wiedzy potrzebnej do wykorzystania możliwości Gita. Aby zrozumieć jak działa Git „od środka” oraz poznać więcej szczegółów dla wymienionych tu poleceń, polecam przeczytanie książki Pro Git.

Drugą ciekawą pozycją jest Git Reference (tym razem w języku angielskim).