Вы находитесь на странице: 1из 18

Tutorial Gita

Jacek Bzdak

1
Spis treści

Spis treści 2

1 Instalacja gita 4
1.1 Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Instalacja dla Cygwina . . . . . . . . . . . . . . . . 4

2 Praca z GITem 5
2.1 Słownik gita . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Proste zastosowania gita . . . . . . . . . . . . . . . . . . . 6
Komitowanie . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Branche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Checkoutowanie . . . . . . . . . . . . . . . . . . . . . . . . 7
Merge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Scenariusz: praca z branchachami . . . . . . . . . . . . . 8
Wycofywanie zmian . . . . . . . . . . . . . . . . . . . . . . 8
Scenariusz: Wycofanie nieskomitowanych zmian . 9
Scenariusz: Wycofanie skomitowanych zmian 1 . . 9
Scenariusz: Wycofanie skomitowanych zmian 2 . . 9
O gorliwości gita i git-stash . . . . . . . . . . . . . . . . 9
2.3 Praca z wieloma repozytoriami . . . . . . . . . . . . . . . . 11
Repozytoria nazwane . . . . . . . . . . . . . . . . . . . . . 11
Kopiowanie repozytoriów . . . . . . . . . . . . . . . . . . . 11
Nagie repozytoria . . . . . . . . . . . . . . . . . . . . . . . 12
Pobieranie danych z repozytorium . . . . . . . . . . . . . . 12
Wysyłanie danych do repozytoriów . . . . . . . . . . . . . 12
Scenariusz: praca ze zdalnym repozyrorium . . . . . . . . 12
Scenariusz: upublicznienie repozytorium po ssh . . . . . 13
Scenariusz: pobranie zawartości repozytorium . . . . . . 13
2.4 Zaawansowana praca z branchami . . . . . . . . . . . . . 13
Rodzaje mergeów . . . . . . . . . . . . . . . . . . . . . . . . 13
Metody mergeowania . . . . . . . . . . . . . . . . . . . . . 14
O nieumieszczanu plików IDE w repozytorium . . . . . . 15
Kasowanie branchy . . . . . . . . . . . . . . . . . . . . . . 15
2.5 Zaawansowane użycia gita . . . . . . . . . . . . . . . . . . 15
Gitignore . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Znaki końca linii . . . . . . . . . . . . . . . . . . . . . . . 16
git-config . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2
Spis treści 3

Punkt w historii . . . . . . . . . . . . . . . . . . . . . . . . 17
Urle które obsługuje git . . . . . . . . . . . . . . . . . . . . 17
Stashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Hardlinki a git-clone . . . . . . . . . . . . . . . . . . . . 18
Czytanie historii . . . . . . . . . . . . . . . . . . . . . . . . 18
Przepisywanie historii . . . . . . . . . . . . . . . . . . . . . 18
git-rebase . . . . . . . . . . . . . . . . . . . . . . . . 18
Scenariusz: Wyciagni˛ ece
˛ podmodułu z kodu. . . . 18
Rozdział 1

Instalacja gita

1.1 Linux
Prosta piłka — należy użyć swojego managera pakietów.
Dla ubuntu/debiana należy wpisać:
sudo apt-get install git-core
Dodatkowo można zainstalować przydatne narzedzia
˛

program do mergeowania Na przykład meld, kdiff3. Te obsługiwane


przez gita natywnie sa˛ wypisane w manie dla git-config w opisie
klucza merge.tool.
edytor tekstu do edycji messagey commiów. Ja nie lubie vi używam
nano.

1.2 Windows
Tu już trzeba cudować. Oficjalny port gita dla windows jest w cygwinie.
. . A jaki cygwin jest wiadomo ;)
Tak czy inaczej mamy takie opcje:

Cygwin
MSGit Natywna implementacja. Ponoć szybsza niź cygwinowa. Nie wiem,
nie bawiłem sie.
˛ Można ja˛ porać ze strony http://code.google.com/p/msysgit/.
Nie wiem nie bawiłem sie.
˛

Instalacja dla Cygwina


Najpierw trzeba ściagn
˛ ać˛ instalator cygwina, nastepnie
˛ należy ścia-
˛
gnać
˛ pakiety dla gita i openssh (jeśli potrzebne jest wsparcie gita wspar-
cia dla ssh).
Jeśli potrzebujesz korzystać z ssh-agent, trzeba jeszcze w pliku
$CYGWIN_FOLDER$\bin\cygwin.bat zamienić ostatnia˛ linie˛ na ssh-agent
bash --login -i.

4
Rozdział 2

Praca z GITem

Filozofia1 gita2 jest zasadniczo różna od filozofii klasycznych systemow


wersjonowania. Repozytorium gita to po prostu dowolny katalog w któ-
rym znajduje sie˛ podkatalog o nazwie .git zawierajacy ˛ dane wersjo-
nowania. Repozytorium po stronie serwera niczym nie różni sie˛ od re-
pozytorium kilenta — albo inaczej — w gicie nie istnieja˛ w ogóle pojecia
˛
serwera i kilenta, repozytoria sa˛ równoprawne.
Zawartość katalogu repozytorium (poza katalogiem .git) to tak
zwana kopia robocza 3 .

2.1 Słownik gita

Wówczas Budda rzekł: <<Bracia istnieja˛ tylko


działania oraz ich skutki, ale nie istnieje osoba,
która działa (...) Nie istnieje żadne indywiduum,
jest tylko umownma nazwa nadana zbiorowi
elementów>>

Nizeznany

Krótkie wyjaśnienie poje˛ ć gita

repozytorium Struktura danych zawierajaca


˛ historie˛ projektu (zawar-
tość katalogu .git).
kopia robocza Bierzaca
˛ wersja projektu na której pracuje programi-
sta.
nazwa Nazwa obiektu Gita to 20 cyfrowy skrót SHA-1 danego obiektu.
obiekt Coś co jest w repozytorium gita. Sa˛ nastepujace
˛ rodzaje obiek-
tów gita: blob4 , drzewa, komity, tagi.
1 „Filozofiato legalne dragi” — madrość
˛ ludowa
2I innych tzw. rozproszonych systenów wersjonowania
3 (z ang.) working copy
4

z ang. binary large object

5
ROZDZIAŁ 2. PRACA Z GITEM 6

blob Reprezentuje plik. Najgłupszy obieky gita. Jego nazwa jest cał-
kowicie determiniowana przez jego zawartość, czyli dwa pliki o
różnych nazwach i położeniach maja˛ jedna˛ i dziela˛ tego samego
bloba.
drzewo Reprezentuje katalog. Zawiera odniesienia do innych drzew i
do blobów. Bloby reprezentuja˛ pliki w danym katalogu, drzewa
— podkatalogi. Drzewo przechowuje też nazwy (nie chodzi mi tu
o nazwy gita, ale o filenames) plików i katalogów które zawiera.
Nazwa drzewa zależy tylko od jego zawartości.
commit Czyli stan projektu w danej chwili czasu. Zawiera odniesienie
do drzewa które reprezentuje główny katalog projektu w chwili
komitowania i komitu rodzica. Zawiera też komentarz, osobe˛ kom-
tujac˛ a˛ i autora zmian5 . Komit nie posiadajacy
˛ rodzica, to tak
zwany root commit który reprezentuje inicjalna˛ wersje˛ projektu.
Commit, który reprezentuje łaczenie
˛ branchy, może mieć wiecej
˛
niż jednego rodzica.
tag Czyli zrozumiała dla człowieka nazwa jakiegoś obiektu. Zawiera
informacje o osobie które ów obiekt otagowała i komentarz. Może
zawierać cyfrowy podpis danego tagu.
index Plik bed
˛ acy
˛ pośrednikiem miedzy˛ kopia˛ robocza˛ a repozytorium.
Podczas komitowania skomitowana nie bedzie ˛ cała zawartość ko-
pii roboczej, a tylko zawartość indexu.
HEAD wskaźnik na bierzacego
˛ brancha

2.2 Proste zastosowania gita


Czyli jak stosować gita na lokalnym komputerze.

Tworzenie repozytorium
By utworzyć repozytorium w bierzacym
˛ katalogu należy wykonać po-
lecenie:
git-init

Dodawanie plików do indexu


Podczas komitowania do repozytorium trafiaja˛ tylko pliki znajdujace ˛
sie˛ w indeksie. By dodać plik do indeksu należy wykonać polecenie:
git-add lista_plików
Ponieważ git-add przyjmuje liste˛ plików można przy nim używać
znaków wieloznacznych np:
git-add *tex
5 W Gicie który powtał na potrzeby jadra
˛ linuxa moga˛ to być dwie różne osoby —
jedna osoba poprawia bład,
˛ kto inny ma prawo do komitowania do repozytorium jadra.
˛
ROZDZIAŁ 2. PRACA Z GITEM 7

Można również dodawać drzewa katalogów, na przykład polecenie:


git-add .
Doda cały bierzacy
˛ katalog.

Komitowanie
By skomitować dodane pliki należy wykonać nastepuj
˛ ace
˛ polecenie:
git-commit [-a] [-m treść wiadomości]
Wyjaśnienie parametrów:
-a Bez tego parametru git skomituje tylko pliki które sa˛ w indeksie –
czyli te o zmianach w których został poinformowany poleceniem
git-add. Z tym parametrem git automatycznie doda wszystkie
zmodyfikowane lub usuniete pliki o które już sa˛ w indeksie, lecz
zignoruje wszystkie nowe pliki.
-m Komentarz komitu. Jest obowiazkowy,
˛ jeśli nie jest on podany git
otworzy w konsoli okno edytora w którym można go napisać. O
tym jak wybrać odpalany przez gita edytor w 2.5 na stronie 16.

Branche
By stworzyć brancha należy wkonać polecenie:
git-branch nazwa_brancha punkt_w_historii

nazwa_brancha Pownna być zrozumiała dla człowieka, nie może za-


wierać spacji. Domyślnie git pracuje w branchu master.
punkt_w_historii Czyli do czego ma sie˛ dany branch odnosić. Jeśli
tego parametru nie podamy branch utworzy sie˛ wskazujac ˛ na
bierzace
˛ położenie.

Uwaga! git-branch tylko tworzy brancha - nie zaczynamy w nim pra-


cować.

Checkoutowanie
Polecenie git-checkout przenosi do kopii roboczej jakiś punkt w hi-
storii.
git-checkout punkt_w_historii

Merge
Czyli łaczenie
˛ branchy. Do łaczenia
˛ branchy służy polecenie:
git-merge nazwa_brancha
Polecenie to przenosi zmiany z brancha nazwa_brancha do bierza-
˛
cego brancha.
ROZDZIAŁ 2. PRACA Z GITEM 8

Scenariusz: praca z branchachami


Załóżmy że zaczynamy w branchu master, który ma zawierać gotowy,
przetestowany kod. Chcemy dokonać jakiejś zmiany w kodzie, ale nie
chcemy by byla ona w tym branchu, puki jej nie przetestujemy. Można
oczywiście zmian nie umieszczać w repozytorium póki nie bed ˛ a˛ one
gotowe, ale przecież po to jest repozytorium, żeby w nim trzmyać kod.
Tworzymy wiec ˛ brancha work w którym bed ˛ a˛ zmiany, wprowadzamy
w nim zmiany, testujemy je, a nastepnie merdżujemy do rbancha master.
Musimy wiec ˛ wykonać nastepujace ˛ polecenia.
Najpierw tworzymy brancha work.
git-branch work
Możemy sprawdzić czy rzeczywiście go utworzyliśmy wywołujac
˛ ko-
mende˛ git-branch bez argumentów która po prostu wyświetla wszyst-
kie branche.
$ git-branch
* master
work
Gwiazdka˛ zaznaczono bierzacy
˛ branch.
Teraz przechodzimy do brancha work.
git-checkout work
Dokonujemy zmian i komitujemy je.
git-commit -a
Po skomitowaniu zmian checkoutujemy brancha master. Musimy
to zrobić gdyż git-merge działa w ten sposób że do bierzacego
˛ brancha
mergeuje inny branch.
git-checkout master
Wykonujemy mergea
git-merge work
Teraz możemy albo przenieść sie˛ do brancha work i dalej pracować
albo np skasować brancha work.

Wycofywanie zmian
Do usuniecia
˛ nieskomitowanych zmian służy polecenie:
git-reset --tryb commit
Tryby sa˛ trzy:

soft Nie resetuje indexu, ani kopii roboczej. Zmienia tylko wskaźnik
heada.
mixed Resetuje indeks, nie dotyka kopii roboczej. Po wywołaniu tego
polecenia żaden z plików nie bedzie
˛ oznaczony jako gotowy do
skomitowania.
ROZDZIAŁ 2. PRACA Z GITEM 9

hard Resetuje indeks i kopie˛ robocza.


˛
Parametr commit to commit na który bedzie
˛ wskazywać HEAD po wy-
wołaniu tego polecenia, jeśli nie podamy tego paramtetru HEAD nie
bedzie
˛ zmieniony.

Scenariusz: Wycofanie nieskomitowanych zmian


Załóżmy że robie˛ refractoring kodu, przy czym decyduje że jakaś zmiana
jednak jest nietrafiona. Żeby wycować wszystkie zmiany musze˛ napi-
sać:
git-reset --hard

Scenariusz: Wycofanie skomitowanych zmian 1


Podobnie jak ostatnio, z tym że zmiany zostały skomitowane. Ciagle ˛
moge˛ je wycofać poleceniem git-reset, jednak jest to potencjalnie dość
groźne. Najpierw jednak polecenie:
git-reset --hard HEAD^
HEAD^ — znaczy rodzic HEAD. Wiecej ˛ o nazwach gita w sekcji 2.5
na stronie 17.
Niebezpieczeństwo jest takie że jeśli gdy któś ów commit wychec-
koutuje i bedzie
˛ nad nim dalej pracować zaczniecie mieć niespójna˛ hi-
storie,
˛ a wtedy git zgłupieje, ziemia sie˛ otworzy i wyjdzie z niej szatan
;).

Scenariusz: Wycofanie skomitowanych zmian 2


Do wycofania opublikowanego commitu służy polecenie git-revert.
Wykonuje ono commit cofajacy ˛ zmiany.
Różnica miedzy
˛ git-reset a git-revert jest taka że jeśli użyjesz
pierwszego to w historii nie pozostanie śladu po złym commicie.

O gorliwości gita i git-stash


Git nigdy nie nadpisze zmian nieznajdujacych
˛ sie˛ w repozytorium —
czyli nigdy nie wykona nieodwracalnych zmian. Coś takiego może sie˛
zdarzyć w kilku przypadkach. Przykładowo mamy w kopii roboczej plik
baz.txt, który jest poza repozytorium (nie był dodany), a w branchu B
(czyli automatycznie w repozytorium) jest plik o tej samej nazwie z inna˛
zawartościa.
˛
Można to zobaczyć na własne oczy:
jb@lucy:~/foo$ git-init
Initialized empty Git repository in /home/jb/foo/.git/
jb@lucy:~/foo$ echo "xxx" > foo.txt
jb@lucy:~/foo$ git-add foo.txt
jb@lucy:~/foo$ git-commit
Created initial commit c073b2e: sa
1 files changed, 1 insertions(+), 0 deletions(-)
ROZDZIAŁ 2. PRACA Z GITEM 10

create mode 100644 foo.txt


jb@lucy:~/foo$ git-branch work
jb@lucy:~/foo$ git-checkout work
Switched to branch "work"
jb@lucy:~/foo$ echo "zzz" > baz.txt
jb@lucy:~/foo$ git-add baz.txt
jb@lucy:~/foo$ git-commit
Created commit 44e60cc: baz
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 baz.txt
jb@lucy:~/foo$ git-checkout master
Switched to branch "master"
jb@lucy:~/foo$ echo "yyy" > baz.txt
jb@lucy:~/foo$ git-checkout work
error: Untracked working tree file ’baz.txt’ would be
overwritten by merge.
jb@lucy:~/foo$ git-merge work
Updating c073b2e..44e60cc
error: Untracked working tree file ’baz.txt’ would be
overwritten by merge.
By problem rozwiazać
˛ należy plik baz.txt dodać do repozytorium:
jb@lucy:~/foo$ git-add baz.txt
jb@lucy:~/foo$ git-commit
Created commit df1cf44: foo
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 baz.txt
jb@lucy:~/foo$ git-checkout work
Switched to branch "work"
jb@lucy:~/foo$ git-checkout master
Switched to branch "master"
jb@lucy:~/foo$ git-merge work
Auto-merged baz.txt
CONFLICT (add/add): Merge conflict in baz.txt
Automatic merge failed; fix conflicts and then commit
the result.
jb@lucy:~/foo$ git-mergetool
Merging the files: baz.txt
jb@lucy:~/foo$ git-commit
Created commit 5fa91f9: Merge branch ’work’
Analogicznie Git sie˛ zachowa jeśli spróbujemy wykonać mergea/com-
mita przy nieskomitowanych zmianach w kopii roboczej.
jb@lucy:~/foo$ git-checkout work
Switched to branch "work"
jb@lucy:~/foo$ echo "jjj" > foo.txt
jb@lucy:~/foo$ git-commit -a
Created commit b04a588: das
1 files changed, 1 insertions(+), 1 deletions(-)
jb@lucy:~/foo$ git-checkout master
ROZDZIAŁ 2. PRACA Z GITEM 11

Switched to branch "master"


jb@lucy:~/foo$ echo "ppp" > foo.txt
jb@lucy:~/foo$ git-merge work
foo.txt: needs update
error: Entry ’foo.txt’ not uptodate. Cannot merge.
fatal: merging of trees
62c4cf4f82d52932a4d2148efa7e80f1807ac6aa and
9923cc607172ca543cb5115f0ce25178a033651a failed
Merge with strategy recursive failed.
Na pierwszy rzut oka jest to upierdliwe, lecz z drugiej strony: chroni
przed nieodwracalnym usunieciem
˛ zmian.

2.3 Praca z wieloma repozytoriami


Repozytoria nazwane
Git posiada mechanizmrepozytoriów nazwanych, które choć to konieczne
do pracy ze zdalnymi repozytoriami bardzo ja˛ ułatwia.
By utworzyć nadać jakiemuś zdalnemu repozytroum nazwe˛ należy
wykonać polecenie:
git-remote add nazwa url

nazwa to nazwa zdalnego repozytorium. Nie może zawierać spacji.


url to url do danego repozytrorium. Przykładowo ˛ może być to Urlem
może być na przykład: ssh://skimbleshanks.ath.cx/var/git/diesIrae6 ,
urlem może też być ścieżka lokalnego systemu plików.

Kopiowanie repozytoriów
Sa˛ dwie metody na kopiowanie repozytoriów.
Pierwsza˛ jest Pierwsza˛ jest polecenie git-clone. Pozwala ono sko-
piować zawartość całego repozytorium.
git-clone url
Po wykonaniu tego polecenia z podanym urlem git zrobi nastepu-
˛
jace
˛ rzeczy:
1. utworzy w bierzacym
˛ katalogu katalog diesIrae
2. zainicjalizuje w nim repozytorium
6 Skimbleshanks is a cat character in T. S. Eliot’s book of poetry Old Possum’s Book

of Practical Cats and in Andrew Lloyd Webber’s musical Cats:


Saying ‘Skimble where is Skimble has he gone to hunt the thimble?
We must find him or the train can’t start.’
All the guards and all the porters and the stationmaster’s daughters
They are searching high and low,
Saying ‘Skimble where is Skimble for unless he’s very nimble
Then the Night Mail just can’t go.’
Źródło: http://en.wikipedia.org/wiki/Skimbleshanks
ROZDZIAŁ 2. PRACA Z GITEM 12

3. ściagnie
˛ zawartość z zadanego repozytorium
4. W repozytorium na tym komputerze utworzy odniesienie o nazwie
origin wskazujace
˛ na danego urla.

Nagie repozytoria
Sa˛ to repozytoria nie majace
˛ kopii roboczej. Maja˛ bardzo ograniczona˛
funkcjonalność — nie można na nich wykonywać wielu operacji (w
zasadzie wszystkich poza komitowaniem kodu i pobieraniem zmian).
Nadaja˛ sie˛ natomiast całkiem nieźle rpeopzytoria w serwerze. Twozy
sie˛ je poleceniem:
git-init --bare

Pobieranie danych z repozytorium


By pobrać zawartośc repozytorium należy wykonać polecenie:
git-fetch nazwa_repozytorium
Spowoduje to pobranie wszystkich branchy z danego repozytorium i
zapisanie ich jako branchy o nazwach: nazwa_repozytorium/nazwa_brancha
Przykładowo, w repozytorium skimbleshanks znajduje sie˛ branch
master wiec
˛ po wykonaniu polecenia:
git-fetch skimbleshanks
powstanie branch o nazwie skimbleshanks/master.

Wysyłanie danych do repozytoriów


By wysłać zmienione pliki do repozytorium należy wykonać:
git-push nazwa_repozytorium wysylany_branch
Polecenie git-push zadziała poprawnie tylko jeśli merge zmian do
brancha na zdalnym repozytrium bedzie˛ typu fast forward, czyli nikt
inny w miedzyczasie
˛ nie zmieni zalnego brancha. Jeśli tak nie bedzie
˛
git-push zwróci bład.
˛

Scenariusz: praca ze zdalnym repozyrorium


Zakładam że pracuje na repozytorium skimbleshanks, w branchu
unstable.
Rano ściagam
˛ ewentualne zmiany z repozytorium:
git-fetch skimbleshanks unstable
Podczas całego dnia wykonuje zmiany w kodzie. Chce˛ teraz moje
zmiany wysłać do zdalnego repozytorium.
Polecenie git-push zadziała poprawnie tylko jeśli merge zmian do
brancha na zdalnym repozytrium bedzie
˛ typu fast forward (dokłanie o
typach merdży w 2.4 na nastepnej
˛ stronie), czyli nasz branch bedzie
˛
zawierał w swojej hisorii HEADa zdalnego brancha. Bedzie ˛ tak jeśli
ROZDZIAŁ 2. PRACA Z GITEM 13

albo nikt nie komitował w miedzyczasie


˛ do zdalnego brancha, albo my
w naszym repozytorium zmergeowaliśmy nowe zdalne zmiany.
Załóżmy że w miedzyczasie
˛ ktoś skomitował coś do tego repozyto-
rium. Musimy zatem nowe zmiany pobrać raz jeszcze:
git-fetch skimbleshanks unstable
Teraz owe zmiany mergeujemy:
git-merge skimbleshanks/unstable
git-mergetool
Po mergeowaniu można już wysłać zmiany:
git-push skimbleshanks unstable

Scenariusz: upublicznienie repozytorium po ssh


Powiedzmy że mam repozytorium na moim lokalnym komputerze, re-
pozytorium zawiera program nad którym mój kolega Adam chce pra-
cować. Może on bezpośrednio pobierać zmiany z mojego repozytorium
(o ma dostep),
˛ ale możemy też ustawić repozytorium na zdalnym ser-
werze i obaj do niego komiować, rozwiazanie
˛ to jest lepsze o tyle o ile
lepiej sie˛ skaluje.
Powiedzmy że serwer nazywa sie˛ skimbleshanks.
Najpierw na zdalnym komputerze tworze nagie repozytorium (ma to
sens ponieważ nikt nie bedzie
˛ na tym repozytorium pracować bezpo-
średnio).
jb@skimbleshanks$ git-init --bare
Nastepnie,
˛ u siebie, tworze repozytorium nazwane:
jb@lucy$ git-remote add skimbleshanks
ssh://skimbleshanks.ath.cx/var/git/diesIrae
Potem przesyłam do repozytorium na skimbleshanks zawartość mo-
jego repozytorium. Wykonuje u siebie polecenie:
jb@lucy$ git-push --all skimbleshanks

Scenariusz: pobranie zawartości repozytorium


Teraz Adam chce pobrać zawartość tego repozytorium. Wykonuje wiec
˛
polecenie:
git clone ssh://skimbleshanks.ath.cx/var/git/diesIrae

2.4 Zaawansowana praca z branchami


Rodzaje mergeów
Sa˛ trzy roadzaje mergeów:
ROZDZIAŁ 2. PRACA Z GITEM 14

Rysunek 2.1: Ilustracja mergea already up to date.

Rysunek 2.2: Ilustracja fast forward merge

Rysunek 2.3: Ilustracja mergea

already up to date Jeśli próbujemy zmergeować commita który już


jest cześci
˛ a˛ historii HEADa. W tym wypadku merge nie wykonuje
żadnej czynności.
fast_forward Odwrotnie: HEAD jest cześci
˛ a˛ historii mergeowanego com-
mita. W tym przypadku nie jest tworzony komit mergeujacy˛ (bo i
nie ma żadnych nowych zmian w repozytorium), po prostu HEAD
jest updejtowany tak że wskazuje na komit merdżowany.
prawdziwy_merge Nie zachodzi żadna z powyższych alternatyw. Trzeba
mergeować recznie
˛ i (opcjonalnie) rozwiazywać
˛ konflikty.

Obrazki powinny rozjaśnić sytuacje,


˛ opisane merdże sa˛ na obrazkach.
Kropki reprezentuja˛ komity. Jeśteśmy w pukcie zaznaczonym żółta˛
kropka˛ i mergeujemy kropke˛ niebieska.
˛

Metody mergeowania
Jeśli w merdżu bed˛ a˛ konflikty (ten sam plik wyedytowany w obu gałe-
˛
ziach) to stana˛ sie˛ nastepuj
˛ ace
˛ rzeczy:

• Git przejdzie w specjalny stan który zabrania wykonywać komity


puki merge nie bedzie
˛ wykonany
• Do plików z konfliktami zosana˛ wyplute conflict markery, które
wygladaj
˛ a˛ mniej wiecej
˛ tak:
ROZDZIAŁ 2. PRACA Z GITEM 15

<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>>
77976da35a11db4580b80ae27e8d65caf5208086:file.txt
Teraz pora na git-mergetool jest to narzedzie
˛ pozwalajace
˛ na roz-
sadzenie
˛ konfliktów.

O nieumieszczanu plików IDE w repozytorium


Taka krótka sprawa. Nieumieszczanie plików generowanych przez IDE
w repozytorium jest dobrym pomysłem w ogóle. Jednak przy używaniu
GITa umieszczanie tych plików ma dodatkowe wady szczególnie jeśli
używamy branchy.
Przy mergeowaniu branchów czesto ˛ w tych plikach bed
˛ a˛ konflikty,
co wiecej
˛ podczas rozwiazywania
˛ takiego mergea może sie˛ okazać że
przestanie działać. Git wypluje do plików konfiguracyjnych markery
konfliktów, przez co IDE może ich nie umieć odczytać! Brrr.
No i jeśli sie˛ okaże że dodamy plik IDE w trakcie pisania projektu
może sie˛ okazać że merge nie wychodza˛ w ogóle — mamy taka˛ sytuacje: ˛
w branchu work dodajemy do repozytorium jakiś plik IDE, który przy
okazji jest modyfikowany przez owo IDE, i od tej pory merdż brancha
master i work bedzie ˛ wypluwać bład
˛ (patrz. 2.2):
jb@lucy:~/foo$ git-merge work
foo.txt: needs update
error: Entry ’.classpath’ not uptodate. Cannot merge.

Kasowanie branchy
Branche można też kasować.
git-brach -d nazwa_brancha
Polecenie to ze switchem -d ma wbudowane zabezpieczenie — wy-
kona sie˛ tylko jeśli ten branch nazwa_brancha jest już wmergeowany
w HEADa.
Jeśli chcemy skasować bracha bez tego sprawdzenia, bo na przy-
kład zawiera on kod którego nie chcemy mergeować należy użyć para-
metru -D:
git-brach -D nazwa_brancha

2.5 Zaawansowane użycia gita


Gitignore
Nie wszystko powinno być w repozytorium. Jeśli jednak mamy grupy
plików których w repozytorium nie chcemy polecenie git-add z argu-
mentem . zaczyna być bezużyteczne.
ROZDZIAŁ 2. PRACA Z GITEM 16

Możemy zatem nakazać Gitowi ignorowanie pewnych wzorców nazw


plików. Zainteresowanych odsyłam do
man gitignore

Znaki końca linii


Znaki końca linii sa˛ zmora˛ jeśli nad programem w jednym repozyto-
rium pracuja˛ użytkownicy *nixów i windowsów.
Git jednak jest w stanie sobie z tym poradzic (z pewnymi ale). Jeśli
ustawimy w konfiguracji klucz core.autoclf na wartość true to git
przy zapisywaniu bedzie
˛ podmieniał sekwencje˛ CRLF na samo LF, a
przy odczycie na odwrót. Warto od razu ustawić opcje˛ core.safeclf,
która pilnuje że konwertowane sa˛ tylko pliki dla których konwersja
jest odwracalna.
Zasadniczym problemem z tym mechanizmem jest to że git może
tak potraktować pliki binarne (generalnie stara sie˛ je wykrywać i nawet
mu to wychodzi — jednak możliwość jest że sie˛ pomyli). Git w obiek-
tach blob nie pamieta nazw plików (wszak jeden blob może mieć kilka
nazw w różnych momentach historii), wiec ˛ wykrywanie binarności pli-
ków musi działać majac ˛ tylko jego zawartość. Opcja core.safeclf
pilnuje że nawet jeśli plik jest jest przez gita uszkadzany zmiana jest
odwracalna (potem sa˛ jakieś mechanizmy oznaczania plików jako pli-
ków binarnych)7 .

git-config
Narzedzie
˛ pozwalajace
˛ konfigurować gita.

Konfiguracja edytora W 2.2 na stronie 7 dowiedzieliśmy sie˛ że


jeśli poleceniu git-commit nie podać komentarza do komita git odpali
edytor. Ponieważ każdy ma swój ulubiony edytor można skonfigurować
polecenie ów edytor włacz˛ acy.
˛ Służy do tego klucz w konfiguracji o
nazwie: core.editor. Na przykład:
git-config --global core.editor emacs
.
Opcje konfiguracji sa˛ dobrze udokumentowane w manie
man git-config

Znaki końca linii Do zarzadzania


˛ traktowaniem znaków końca
linii służa˛ klucze: core.autoclf i core.safeclf. Patrz akapit 2.5.
7 Dla mnie cała ten wywód to wyższa magia i jest on mało interesujacy — w moich

repzoytoriach nie ma plików binarnych (poza wyjatkami


˛ w stylu: wrappery .exe ktore
odpalaja˛ moje programy javy, które to wyjatki
˛ i tak da sie˛ łatwo odtworzyć). Zależno-
ściami zajmuje sie˛ maven i ich nie ma w repozytorium.
ROZDZIAŁ 2. PRACA Z GITEM 17

Punkt w historii
Historia gita sklada sie˛ z grafu komitów, historia brancha to linia co-
mitów. Każdy punkt historii jest dostepny
˛ po nazwie komitu. Nazwy
gita sa˛ raczej nieporeczne
˛ — wszak to 20 cyfrowe hasze SHA-1. Za-
miast całeho SHA-1 można podać jego poczatek˛ — o ile poczatek
˛ jest
unikalny w repozytorium. Tak wiec ˛ zamigit-resetast
git-checkout 980e3ccdaac54a0d4de358f3fe5d718027d96aae
Można napisać:
git-checkout 980e3cc
Jest też kilka innych możliwości:

nazwa barancha Punktem w historii jest też nazwa brancha — wska-


zuje on na najświeższy commit w branchu.
nazwa tagu Tag to de facto commit.
HEAD Czyli najświeższy comit w aktualnym branchu.
Rodzice Można odnieść sie˛ też do rodziców danego commita. HEAD^ to
rodzic HEADa. Można też zapytać o dalszych rodziców horzystajac
˛
z HEAD@{n}, gdzie n to poszukiwane pokolenie.

Urle które obsługuje git


Git obsługuje różne i różniaste rodzaje urli:

lokalne pliki Podajemy po prostu absolutna˛ ścieżke˛ do danego kata-


logu.
git-clone /var/git/diesIrae

ssh Przykłady były


http Choć ustawienie repozytorium HTTP gita nie jest bardzo łatwe8 ,
to można łatwo pobierać repozytorium gita za pomoca˛ tego pro-
tokołu.
http://foo/git/diesIrae

Wszystkie możliwości urla sa˛ opisane w manie dla git-clone.


8 Nie jest też jakoś trudne ;) po prostu sie˛ na tym nie znam totalnie.
ROZDZIAŁ 2. PRACA Z GITEM 18

Stashing
Hardlinki a git-clone
Czytanie historii
Przepisywanie historii
git-rebase
Scenariusz: Wyciagni
˛ ece
˛ podmodułu z kodu.
Mam projekt który stanowi gui dla takiego sprzetu ˛ spektrometrycz-
nego. Kawałkiem projektu jest biblioteka, i teraz owa˛ biblioteke˛ chce˛
z projektu wyciać˛ i przenieść do własnego repozytorium, tak by za-
chwoać cała˛ historie˛ owej biblioteki.
W zasadzie git ma standardowe narzedzia ˛ do zarzadzanai
˛ podmo-
dułami, ale ja jestem na to troszke˛ za głupi.
Znalazłem wiec ˛ projekt git-subtree, który robi dokładnie to, nie jest
to cześć
˛ standardowego gita, ale działa.
Najpierw trzeba to sobie ściagn˛ ać
˛ i umieścić gdzieś w pathu. Ścia-
gamy z http://github.com/apenwarr/git-subtree. Interesuje nas plik
git-subtree.sh.
Zakładamy że biblioteka jest w podkatalogu o nazwie libdir.
git-subtree --prefix libdir -b lib-export
Utworzy to nam brancha o nazwie lib-export zawierajacego
˛ wszyst-
kie commity dotykajace
˛ katalogu libdir.
Teraz tworzymy repozytroium i wykonujemy:
git-push url_repozytorium lib-export

Вам также может понравиться