Korzystanie z programu Git (index)


Korzystanie z programu Git (3) - repozytoria z rozgałęzieniami

WPROWADZENIE

Gałęzie Gita są wskaźnikami rewizji. Znaczniki są nieruchome, natomiast gałęzie automatycznie przesuwają się po utworzeniu nowej rewizji. Git jest zoptymalizowany pod względem obsługi gałęzi. Testowanie nowych pomysłów warto robić przy użyciu gałęzi.

Przykładowy diagram repo o historii nieliniowej.


        o--o--o <-- Branch A
       /
o--o--o--o <-- master <-- HEAD
       \
        o--o--o <-- Branch B

TWORZENIE GAŁĘZI LOKALNYCH


$ git branch                  # istniejące gałęzie lokalne
* master                      # gwiazdka wskazuje gałąź bieżącą

# Skrócona informacja o plikach i nazwa gałęzi bieżącej.
$ git status -sb
## master                     # tu nie ma plików zmienionych

# Historia repo:
# A--B--C <-- master <-- HEAD

# git branch [branch_name] [sha1]

$ git branch testing          # utworzenie nowej gałęzi przy bieżącej rewizji

# A--B--C <-- master <-- HEAD
#       ^
#       |
#       testing

$ git branch
* master                      # gałąź bieżąca
  testing

$ git checkout testing        # przełączenie się do nowej gałęzi
Switched to branch 'testing'

# A--B--C <-- master
#       ^
#       |
#       testing <-- HEAD

$ git branch
  master
* testing                     # gałąź bieżąca

# W jednym kroku utworzenie nowej gałęzi i przełączenie się do niej.
# git checkout -b [branch_name] [sha1]

# Zmiana nazwy gałęzi lokalnej.
# git branch -m [old_name] [new_name]   # lub --move
# git branch -M [old_name] [new_name]   # wymuszenie zmiany nazy

USUWANIE GAŁĘZI LOKALNYCH

Bezpiecznie można usunąć gałąź, która została włączona (merge) do upstream branch. Nie można usunąć gałęzi bieżącej.


# git branch -d [branch_name]           # lub --delete
# git branch -D [branch_name]           # wymuszenie usunięcia gałęzi

ZAGUBIONE REWIZJE

Zagubione rewizje (ang. dangling commits) to rewizje nieosiągalne za pośrednictwem gałęzi. Zagubione rewizje są po pewnym czasie automatycznie usuwane z repozytorium. Pewne polecenia Gita automatycznie usuwają zagubione rewizje.


$ git prune         # wymuszenie czyszczenia repozytorium

ŁĄCZENIE GAŁĘZI LOKALNYCH

Przy łączeniu gałęzi można wyróżnić dwa przypadki:

Przewijanie do przodu zachodzi wtedy, gdy jedna gałąź zawiera się w drugiej. Można wykonać przewijanie do przodu dla wielu gałęzi na raz.


# A--B--C <-- master
#        \
#         D--E <-- testing <-- HEAD

$ git branch
  master
* testing           # gałąź bieżąca

$ git checkout master
Switched to branch 'master'

$ git branch
* master            # gałąź bieżąca
  testing

# A--B--C <-- master <-- HEAD
#        \
#         D--E <-- testing

$ git merge testing
Updating cccc..eeee
Fast-forward
...

# A--B--C--D--E <-- master <-- HEAD
#             ^
#             |
#             testing

ŁĄCZENIE GAŁĘZI LOKALNYCH ROZŁĄCZNYCH

Podczas łączenia gałęzi mogą pojawić się konflikty. Jeżeli zmiany w różnych gałęziach dotyczyły różnych plików, to nie powinno być konfliktów.


# A--B--D <-- testing
#     \
#      C <-- master <-- HEAD

$ git branch
* master                      # gałąź bieżąca
  testing

$ git merge testing           # uruchamia się edytor do komentarza
Merge made by the 'recursive' strategy.
...

$ git log
commit eeee
Merge: cccc dddd
Author: Andrzej Kapanowski <andrzej.kapanowski@uj.edu.pl>
Date:   Wed Dec 16 09:55:30 2015 +0100

    Merge branch 'testing'

# A--B--D <-- testing
#     \  \
#      C--E <-- master <-- HEAD

$ git log --pretty=oneline
eeee Merge branch 'testing'
dddd D                        # było tylko w testing
cccc C                        # było tylko w master
bbbb B
aaaa A

# Można przesunąć gałąź testing, aby robić nowe testy.

$ git checkout testing

$ git merge master   # fast forward do rewizji E

# A--B--D
#     \  \
#      C--E <-- master
#         ^
#         |
#         testing <-- HEAD

# Usuwanie łączenia gałęzi wykonanego za pomocą git merge:
# git reset --hard HEAD~   # lub HEAD^

# Lista gałęzi, których tips są osiągalne z rewizji sha1:
# git branch --merged

# Lista gałęzi, których tips nie są osiągalne z rewizji sha1:
# git branch --no-merged

# Sprawdzanie różnic pomiędzy gałęziami:
# git diff --name-status branch1_name branch2_name

OPERACJA GIT REBASE

Innym sposobem łączenia gałęzi jest operacja "git rebase". Po tej operacji projekt ma historię liniową. Jeżeli gałąź bieżąca jest zawarta w gałęzi dołączanej, to "git rebase" jest równoważne "git merge".


# A--B--D <-- testing
#     \
#      C <-- master <-- HEAD

$ git checkout master

$ git rebase testing
First, rewinding head to replay your work on top of it...
Applying: C

#       testing
#       |
#       v
# A--B--D--C' <-- master <-- HEAD
#
# Uwaga: C' ma inne sha1 niż C przed rebase. D jest takie samo.
# Wniosek: nie stosować rebase do rewizji publicznych.

# Można przesunąć gałąź testing, aby robić nowe testy.

$ git checkout testing

$ git merge master            # fast forward do rewizji C'

#          testing <-- HEAD
#          |
#          v
# A--B--D--C' <-- master

# W manualu jest przykład "git rebase" z poziomu gałęzi testing.
# To wydaje się lepsze, jeżeli master jest powiązane ze zdalnym repo.
# A--B--D <-- testing <-- HEAD
#     \
#      C <-- master

$ git checkout testing

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: D

#       master
#       |
#       v
# A--B--C--D' <-- testing <-- HEAD

$ git checkout master

$ git merge testing           # fast forward do rewizji D'

#          master <-- HEAD
#          |
#          v
# A--B--C--D' <-- testing

Usuwanie operacji "git rebase" jest dość skomplikowane, używa się dziennika reflog . Jeżeli operacja "git rebase" nie uda się, wtedy repo jest w stanie "detached HEAD". Operację taką możemy anulować poleceniem


$ git rebase --abort

ZADANIE 3.1


Korzystanie z programu Git (index)