Archiwa tagu: git

A więc do tego służy git rebase!

Miałam zakończyć raportowanie postępów w nauce systemu kontroli wersji Git, ale właśnie zrozumiałam coś istotnego.

Lubię często wysyłać stan pracy do repozytorium – czuję się wtedy bezpiecznie (chociaż akurat Eclipse jest dość pomocny jeśli chodzi o odzyskiwanie wersji z lokalnej historii). Podczas pracy nad poprzednim wpisem wysłałam do swojego lokalnego repozytorium Git masę głupich „testowych” commitów. Byłam przekonana, że nie zostawią śladu w ostatecznej wersji w GitHub. Tyle że… zostawiły! Przy wypychaniu zmian do repozytorium zdalnego przekazywana jest tam cała historia. O wstydzie, o chaosie!

Podczas dzisiejszych eksperymentów z silnikiem szablonów Thymeleaf, nauczona doświadczeniem oraz komentarzami do wcześniejszego wpisu, postanowiłam skorzystać z opcji git rebase -i, która pozwala interaktywnie uporządkować i scalić commity. W ten sposób do zdalnego repozytorium w serwisie GitHub trafi ostateczny i kontrolowany wynik mojej pracy, a nie poszczególne jej fragmenty.

A było tak:

1. Potrzebowałam trzech commitów, żeby przy użyciu Thymeleaf zwrócić użytkownikowi powitalną stronę:

Aktualny stan aplikacji (commit bbafde0)
Aktualny stan aplikacji (commit bbafde0)

2. Eclipse jak zwykle trzymał rękę na pulsie:

O trzy kroki do przodu względem zdalnej gałęzi master
O trzy kroki do przodu względem zdalnej gałęzi master

3. Nie potrafię użyć interaktywnego rebase w Eclipse, dlatego na chwilę przenoszę się do konsoli:

4. Konsola gita usłużenie wyświetla mi plik w edytorze vim, który to edytor zawsze jest mile widziany pod Windowsem (not):

Co mogę zrobić z moimi trzema commitami?
Co mogę zrobić z moimi trzema commitami?

Edycja pliku pociągnie za zmianę historii repozytorium. Na samej górze widać moje trzy commity i towarzyszące im opisy. Poniżej mam bardzo czytelną instrukcję. Słowo pick na początku każdej z trzech linii odpowiadających commitom mogę zamienić na jedną z dostępnych komend.

5. Oto mój wybór:

Zdecyduj się, człowieku!
Zdecyduj się, człowieku!

Zdecydowałam, że chcę wcielić dwa ostatnie commity do pierwszego i odrzucić ich opisy (fixup), a także zmienić opis pierwszego commita (reword).

6. Po zamknięciu i zapisaniu pliku pojawia się kolejny, w którym mogę edytować opis jedynego pozostałego przy życiu commita:

Nowy komentarz do commita
Nowy komentarz do commita

7. Wracam do konsoli, gdzie czeka na mnie podnoszący na duchu komunikat:

8. Wracam do Eclipse. Po odświeżeniu projektu widzę, że rzeczywiście commity w lokalnym repozytorium zostały scalone do jednego:

Tylko jeden krok do przodu względem zdalnej gałęzi master
Tylko jeden krok do przodu względem zdalnej gałęzi master

9. Wypycham kod do GitHuba. Tym razem na stronie widać jeden kompletny commit, a nie zbieraninę drobnicy, jak poprzednio.

Jeden commit zamiast trzech
Jeden commit zamiast trzech

PS. Zrozumiałam już, że mimo że jestem tu sama, nie powinnam pracować w gałęzi master. Mam natomiast wątpliwości związane z wypychaniem chwilowych branchy do GitHuba. Może wypowie się któryś z moich gitowych pomocników?

PS2. To jest czwarty wpis na temat Gita. Poprzednie to:

Git: przedzieram się przez gałęzie

System kontroli wersji Git był tematem dwóch niedawnych wpisów na moim blogu: No i Git! Kontrola wersji służy nie tylko programistom oraz Git w Eclipse. W tym odcinku chcę na jakiś czas zamknąć temat. Skoncentruję się na kwestii odgałęzień w kodzie (branches).

Git pozwala na przyjemną i efektywną pracę z branchami. Łatwo je tworzyć, scalać i usuwać. Wczoraj zabrałam się za tworzenie szkieletu mojej konkursowej aplikacji Szafbook i wykorzystałam to jako pretekst do poeksperymentowania z odgałęzieniami.

Ogólny zarys moich działań
  1. Utworzenie nowego brancha w konsoli.
  2. W ramach brancha: przygotowanie szkieletu aplikacji Spring Boot za pomocą serwisu https://start.spring.io/.
  3. Wcielenie zmian z nowego brancha do głównej linii kodu (konsola).
  4. Utworzenie brancha przez interfejs Eclipse.
  5. W ramach brancha: prace mające doprowadzić kod do stanu, w którym się kompiluje.
  6. Wcielenie zmian z nowego brancha do głównej linii kodu (Eclipse).
  7. Ustalenie, dlaczego nie było mi potrzebne słowo rebase.
Konsola

W oparciu o informacje w odpowiednim rozdziale podręcznika, tworzę nową gałąź (o nazwie bootinit):

Powyższe polecenie jest skrótem dla dwóch innych, z których pierwsze tworzy brancha, a drugie mnie do niego przenosi:

Następnie wprowadzam swoje zmiany. W tym wypadku to wrzucenie szkieletu aplikacji webowej do katalogu projektowego oraz usunięcie niepotrzebnych mi już plików.

Po wprowadzeniu zmian polecenie git status zwraca następującą informację):

5
Wynik wywołania polecenie git status w nowej gałęzi po wprowadzeniu zmian

Chcę śledzić wszystkie te zmiany i chcę je uwzględnić w kolejnym commicie, dlatego dodaję wszystko:

Alternatywnie mogłabym zaznaczyć poszczególne zmienione i dodane pliki poleceniem git add <plik>, a usunięte pliki poleceniem git rm <plik>.

Na tym etapie postanawiam wysłać swoje zmiany do repozytorium:

Załóżmy, że moje prace w gałęzi bootinit osiągnęły taki poziom dojrzałości, że chcę scalić je z główną gałęzią kodu (master).

W tym celu muszę przejść do gałęzi, do której mam wrzucić zmiany i tam wywołać polecenie merge.

8
Merge. Kolory bardzo przyjemne

Jeśli gałąź nie będzie mi już potrzebna, mogę ją usunąć:

I już.

Eclipse

Teraz przerzucam się na pracę w środowisku Eclipse. Na początku importuję istniejący projekt z repozytorium Git.

W Eclipse narzędzia związane z kontrolą wersji znajdują się w menu kontekstowym projektu, w zakładce Team.

Kontrola wersji w Eclipse
Kontrola wersji w Eclipse

Tworzę nową gałąź korzystając z opcji wyświetlonej na powyższym obrazku: Team->Switch To->New Branch

Nazwa aktualnej gałęzi jest wyświetlana przy nazwie projektu.

Nazwa aktualnej gałęzi jest wyświetlana przy nazwie projektu.
Wersja projektu w gałęzi eclipsebranchtest

Dalej wprowadzam swoje zmiany. Przed wszystkim chcę doprowadzić aplikację do stanu, w którym kompiluje się bez błędów (za pomocą Mavena) i zawiera chociaż jeden (bezsensowny na razie) test jednostkowy.

Jedna ze zmian to oznaczenie części plików w katalogu projektu jako ignorowanych – mam na myśli pliki stanowiące wynik kompilacji. W systemie kontroli wersji chcę trzymać tylko źródła.  W menu mamy odpowiednią opcję Ignore, która jest powiązana ze zrozumiałym dla Gita plikiem .gitignore.

Praca w ramach jednej gałęzi została już umówiona w poprzednim wpisie. Załóżmy teraz, że wszystkie zmiany zostały wysłane do repozytorium, a prace w ramach nowej gałęzi eclipsebranchtest zostały zakończone.

Podobnie jak w przypadku pracy w konsoli, najpierw muszę przejść do gałęzi, do której chcę wcielić zmiany (w tym wypadku to master). Tam z menu Team wybieram opcję Merge. Pojawi się okienko przedstawione na poniższym obrazku.

Wybór gałęzi do scalenia
Wybór gałęzi do scalenia. Wybieram eclipsebranchtest

No i to by było na tyle! Mogę jeszcze usunąć niepotrzebną już gałąź w Team->Advanced->Delete Branch.

Rebase

Spodziewałam się, że podczas zabawy z branchami dotrę do momentu, w którym potrzebne stanie się słówko rebase, ale tak się nie stało. Nie pozostało mi nic innego jak RTFM. Oto, co ustaliłam (w wielkim skrócie):

Scalać można albo przy użyciu merge, albo rebase.  W zależności od dokonanego wyboru, inaczej będzie wyglądała historia zmian w projekcie. Po merge historia będzie dokładnie odwzorowywała to, co się działo – wszystkie rozgałęzienia i powroty. Dla odmiany rebase pozwala nieco przepisać historię, w taki sposób, że – mimo pracy w odgałęzieniach – wygląda ona na liniową. Nie jest to prawda historyczna, ale ta forma może okazać się znacznie bardziej czytelna.

[edit: popełniłam jeszcze jeden wpis na temat rebase]

PS.

Wrócę z tematem Gita, jak dorobię się pierwszego poważnego konfliktu w kodzie.

Git w Eclipse

W poprzednim wpisie nauczyłam się – a może przy okazji chociaż jednego Czytelnika – jak kontrolować wersje programu przy użyciu systemu Git i serwisu GitHub. Dzisiaj postanowiłam sprawdzić, jak powiązać repozytorium Git ze środowiskiem programistycznym Eclipse, w którym zamierzam rozwijać swój projekt. Szczególnie ciekawiło mnie, w jaki sposób Eclipse rozwiązuje kwestię dwóch poziomów repozytorium: lokalnego na dysku i zdalnego w chmurze (GitHub).

Gdyby na tym etapie ktoś chciał zwrócić mi uwagę, że rozwijam swój projekt od d**y strony, to uprzejmie informuję, że jestem tu imperatorem. Moim celem jest przede wszystkim nauczenie się czegoś w przyjemny sposób. Jeśli kiedyś w końcu wyjdzie z tego produkt – tym lepiej.

Poniżej przedstawiam kroki potrzebne do powiązania mojego kodu w GitHub z projektem w środowisku Eclipse.

  1. Instalacja Eclipse, oczywiście. W moim przypadku jest to wersja Mars dla programistów Java Enterprise Edition. Nie twierdzę, że to bezsprzecznie najlepsze IDE, ale zamierzam używać go w konkursowym projekcie. Tutaj można znaleźć opisy najpopularniejszych darmowych edytorów dla Javy (po angielsku).
  2. Instalacja w Eclipse narzędzia EGit.

    Help->Install New Software
    Help->Install New Software->http://download.eclipse.org/egit/updates/
  3. Stworzenie nowego projektu w oparciu o istniejący kod.

    import
    File->Import->Projects from Git
  4. Wybranie jednej z dwóch opcji: nowe lokalne repozytorium z kodem z GitHub (clone) lub istniejące lokalne repozytorium powiązane wcześniej z GitHub (np. to, które stworzyłam w konsoli na potrzeby poprzedniego wpisu).

    clone
    Klonowanie!
  5. Podanie adresu projektu w GitHub

    clone2
    W przypadku publicznego repozytorium w GitHub wystarczy podać link
  6. Wybór gałęzi – u mnie na razie jest tylko jedna, główna.

    clone3
    Co by tu wybrać?
  7. Podziwianie zaimportowanego projektu.

    project
    Tak wygląda projekt zsynchronizowany z repozytorium Git
  8. Zmiany w kodzie. Zmodyfikowałam treść jednego pliku i dodałam jeden nowy. EGit natychmiast bardzo wyraźnie sygnalizuje te zmiany.

    project2
    Jeden plik zmieniony, jeden plik utworzony, ale jeszcze nie wersjonowany
  9. Wyświetlenie menu kontroli wersji (opcja Team w menu kontekstowym projektu). Ponieważ chcę dodać do kolejnego commita wszystkie wprowadzone zmiany, wybieram opcję Add to Index (w konsoli to git add).

    team1
    Menu kontroli wersji w projekcie
  10. Zmieniły się ikonki! Zmiany zostały oznaczone jako zaplanowane do wysyłki (staged), ale ciągle nie nastąpił commit.

    team2
    Przed commitem
  11. Wybranie z menu opcji Commit. Do wyboru mamy – i to jest moment, na który czekałam – wysłanie zmian tylko do lokalnego repozytorium, bądź wysłanie ich i lokalnie, i dalej, do GitHub.

    team3
    Wysyłamy zmiany
  12. Mniej więcej na tym etapie nastąpi wreszcie prośba o logowanie.

    credentials
    To repozytorium jest otwarte dla wszystkich do odczytu, ale tylko wybrańcom wolno wysyłać do niego kod
  13. Zdecydowałam się na wysyłkę z jednoczesnym wypchnięciem kodu do GitHub (może niezbyt rozsądnie, ale wszystko to w ramach eksperymentu). Sprawdzę teraz, czy moje zmiany są widoczne w serwisie.

    github
    Co słychać w GitHub? Wprawne oko zauważy w commicie plik, o którym nie wspominałam wcześniej. Zagadka: dlaczego tam trafił?
  14. Historię zmian mogę podejrzeć także od strony IDE.

    view
    Praca wre

Jak na razie, wszystko przebiegło bardzo intuicyjnie. W najbliższym czasie postaram się utworzyć rozłączne gałęzie kodu z konfliktującymi zmianami (tu wstaw szatański śmiech).

Więcej informacji na temat korzystania z EGit znajdziesz w instrukcji użytkownika.

PS. Mam bardzo silne skojarzenie z wyrazem eclipse (zaćmienie). W wieku wczesnonastoletnim, podczas wakacji nad polskim morzem, namówiłam tatę i siostrę na pójście do kina. Grali akurat film z młodym Leo DiCaprio, w którym kochała się połowa podstawówki. Film nazywał się Całkowite zaćmienie i traktował, jak się okazało, o zakazanej homoseksualnej miłości.  Obejrzenie tego w obecności rodzica zdecydowanie plasuje się w top 5 najbardziej żenujących sytuacji w moim życiu.

No i Git! Kontrola wersji służy nie tylko programistom

To pierwszy z dwóch wpisów, który chcę poświęcić tematowi kontroli wersji za pomocą Gita. Pierwszy będzie wprowadzający i nie pojawi się w nim słowo rebase. W drugim się pojawi, ponieważ jestem nim zaintrygowana. Obu towarzyszyć będą commity do mojego repozytorium projektowego w ramach konkursu Daj się poznać.

Wstęp (dla informatyków)

Zacznę od wyjawienia wstydliwej prawdy: nie znam się Gicie. Tak  wyszło, że w pracy najpierw używaliśmy CVS, potem SVN, potem Perforce (P4). To już i tak niezły mętlik – prosta komenda checkout w SVN i P4 znaczy coś zupełnie odmiennego : odpowiednio pobranie projektu na lokalny dysk albo otwarcie pliku do edycji wraz z zablokowaniem wersji na serwerze. Kilka razy w życiu musiałam dotknąć Gita bądź GitHuba: głównie w zadaniach domowych na Courserze bądź w ramach współpracy z zespołami, które z Gita korzystały.

Życie zmusiło mnie nawet do napisania (wraz z kompanami, co chyba jeszcze pogarsza sprawę) kodu, który automatycznie synchronizował dane w Gicie z danymi w Perforce. Istnieje, co prawda, odpowiedni plugin do P4, ale mieliśmy zbyt starą wersję serwera…

 

Wstęp (dla tych, co nie lubią „tajemniczych szyfrów”*)

System kontroli wersji to narzędzie, które pozwala śledzić zmiany wprowadzane w dokumencie. Dzięki temu zawsze możesz sprawdzić, Wiesz kto i kiedy wprowadził zmianę (czyli dodał, usunął lub zmienił linijkę tekstu). Jeśli zmiany są wprowadzane przez kilka osób, możesz łatwo (a przynajmniej łatwiej niż w innych okolicznościach) je połączyć. Możesz przywrócić dowolną wersję dokumentu – nawet taką, która w rzeczywistości nigdy nie istniała (np. zawierającą zmiany wprowadzone przez dwie osoby, a bez zmian trzeciej).

Systemy kontroli wersji służą przede wszystkim programistom, ale mogą przydać się właściwie każdej osobie pracującej z tekstem, jak dziennikarz czy tłumacz. Można zresztą pilnować w ten sposób nawet listy zakupów… Żeby jednak w pełni skorzystać z funkcjonalności takiego systemu (np. porównywanie dwóch różnych wersji) dane powinny być w postaci czysto tekstowej – takiej, jaką da się otworzyć za pomocą zwykłego edytora tekstu (jak windowsowy Notatnik).

Obecnie najpopularniejszym systemem kontroli wersji jest Git, któremu poświęcony jest ten wpis. Znalazłam nawet artykuł (po angielsku) o tym, jak wersjonować w Gicie pliki MS Word. Do domowych zastosowań wystarczy prostszy koncepcyjnie Subversion.

* Dostałam dzisiaj taką miłą recenzję: Twojego bloga czyta się jednym tchem (gdy pomijam oczywiście wpisy poświęcone jakimś tajemniczym szyfrom ;)).

 

Anegdotka

Żeby nie musieć od razu zabierać się do pracy, opowiem jeszcze anegdotkę.

Zostałam kiedyś zaproszona do wygłoszenia wykładu na temat ciągłej integracji. Połowę czasu spędziłam na live coding (yeah). Pokazałam, jak stworzyć projekt i buildy na serwerze Bamboo (w chmurze firmy Atlassian), oraz w jaki sposób można uruchomić (wyzwolić) plany. Ponieważ na moim prezentacyjnym netbooku z Windows 8 (teraz mieszka tam Linux Mint, więc powstrzymajcie kamienie) nie miałam zainstalowanego żadnego systemu kontroli wersji, wyedytowałam plik w GitHubie (kod też miał być w chmurze) przez przeglądarkę.

Na koniec organizator tego spotkania (który zresztą również bierze udział w konkursie) zwierzył mi się, że o ile treść wykładu zawierała informacje już mu znane, to nie miał pojęcia, że można zmieniać kod w GitHubie z poziomu przeglądarki i to właśnie z tego wykładu wyniesie.

Treść wykładu można znaleźć na blogu: Ciągła Integracja: anioł stróż dobrego programisty i Ciągła Integracja: jak skonfigurować proces budowania na serwerze Bamboo?

 

Git: cechy charakterystyczne

  • System rozproszony: programiści utrzymuję własne lokalne repozytoria i tylko czasami wysyłają kod do repozytorium głównego.
  • Łatwość tworzenia i scalania gałęzi (branches) do pracy nad różnymi wersjami czy funkcjonalnościami.
  • Staging Area: można wygodnie wskazać, które spośród wprowadzonych zmian mają się znaleźć w commicie, nawet jeśli dotyczą tego samego pliku.
  • Darmowe narzędzie z otwartymi źródłami.

githubheart

Do rzeczy: jak wersjonować projekt w Gicie i przechowywać w ogólnodostępnym repozytorium GitHub?

W 12 krokach:

1. Zainstalować Git w wersji dla odpowiedniego systemu ze strony https://git-scm.com/downloads.
2. Utworzyć konto na stronie GitHub: https://github.com/
3. Utworzyć repozytorium dla projektu

W tym celu należy wybrać na stronie opcję New Repository i wybrać pożądane opcje (repozytorium publiczne lub prywatne, puste lub z plikiem Readme.md; można dodać informację o licencji oraz ignorowanych typach plików). W ten sposób powstało repozytorium mojego projektu.

(GitHub oferuje dodatkowe możliwości, jak strony Wiki czy możliwość zgłaszania błędów – ale o tym nie będziemy tu rozmawiać.)

4. Pobrać kod, tworząc przy okazji lokalne repozytorium

W wybranej przeze mnie lokalizacji wywołuję komendę:

Zawartość katalogu szafbook:

Jeśli przyjrzymy się dokładniej, znajdziemy jeszcze ukryty katalog z informacjami dla systemu kontroli wersji:

Nie będziemy tam zaglądać.

5. Status

Na wszelki wypadek sprawdźmy teraz status plików projektowych i upewnijmy się, że działamy na aktualnej wersji gałęzi MASTER (główna i domyślna gałąź repozytorium):

6. Pora coś popsuć! Zmiana w kodzie

Wprowadziłam zmianę w pliku README.md. Po jej zapisaniu:

7. Dodanie pliku

Utworzę jeszcze nowy plik w tym samym katalogu. Nazwę go test.txt. Po zapisaniu:

Git pokazuje mi, co zmieniłam, a także informuje mnie, że jeśli chcę odwzorować te zmiany w repozytorium, muszę użyć komendy add.

8. Staging: pomiędzy zmianą a commitem

Ponieważ chcę zapisać zmiany w repozytorium, użyję komendy add:

9. Wysłanie zmian do repozytorium

Uwaga 1: Na razie do mojego repozytorium na dysku, a nie do centralnego repozytorium GitHub!)
Uwaga 2: Na tym etapie git może poprosić o podanie informacji o użytkowniku.

W domyślnym edytorze tekstu otwarty zostanie plik z informacjami na temat aktualnego zestawu zmian, gdzie należy wprowadzić objaśniający komentarz.

Alternatywnie mogę podać ten komentarz od razu przy wywołaniu polecenia commit:

10. Historia zmian

Historię zmian możemy śledzić za pomocą komendy log:

11. Wysłanie zmian do centralnego repozytorium GitHub

  • origin to repozytorium, z którego oryginalnie pobrałam kod (czyli mój projekt w GitHub, zapamiętany przy wywołaniu polecenia clone)
  • master to nazwa gałęzi w repozytorium

Uwaga: gdyby w międzyczasie ktoś zmienił kod w głównym repozytorium, musiałabym najpierw zaakceptować jego zmiany – system nie pozwoliłby mi wysłać moich. W tym wypadku jestem jednak jedyną osobą z prawem zapisu, więc mam pewność, że nie natknę się na tego typu kłopoty.

12. Podejrzenie zmian

Na tym etapie moje zmiany są już widoczne w portalu GitHub! Hurra!

 

Więcej?

Więcej informacji: np. jak cofnąć wprowadzone zmiany, odkopać starszą wersję, poradzić sobie ze zmianami wprowadzonymi przez różnych użytkowników, znajdziesz w podręczniku na oficjalnej stronie Gita. Jesteśmy teraz w rozdziale Git Basics.