Lab 5 - GIT — IPP 2011/12

Spis treści

Poprzedni temat

Lab 4 - Object Pascal, testy i GDB

Następny temat

Lab 6

Lab 5 - GIT

Wstęp

Systemy kontroli wersji służą do przechowywania plików źródłowych i śledzenia zmian w nich zachodzących. Pozwalają na
  • koordynowanie zmiany wprowadzanych jednocześnie przez wielu członków zepołu,
  • równolegle rozwijanie kilku wersji projektu i przenoszenie zmian między nimi,
  • analizowanie zmian w celu ustalenia przyczyny błędu lub kontroli nad rozwojem projektu.
  • ...

Istnieje wiele systemów spełniających wspomniane funkcje. Najczęściej stosowanym z nich jest Subversion - wprowadzenie do tego narzędzia można znaleźć na Ważniaku:

http://wazniak.mimuw.edu.pl/index.php?title=%C5%9Arodowisko_programisty/Zarz%C4%85dzanie_wersjami_-_Subversion

Na laboratorium IPP sotsowany będzie nieco inny system - GIT. Jego podstawowy opis mozna znaleźć w poniższych notatkach. Dokładniejsze informacje można uzyskać na stronie http://book.git-scm.com/ .

Obiekty

Rdzeniem systemu GIT jest baza danych, przechowująca obiekty czterech, opisanych poniżej typów. Każdy obiekt ma następujące cechy
  • Jest jednoznacznie identyfikowany przez sumę kontrolną swojego typu i zawartości. Nie może więc być dwóch różnych obiektów o tej samej zawartości - i to nie tylko w ramach jednego repozytorium.
  • Wartość obiektu nigdy nie ulega zmianie. W pewnych okolicznościach obiekt może jednak zostać usunięty.
  • Obiekty większości typów zawierają referencje do innych obiektów.

Oprócz referencji zawartych w obiektach istneiej także kilka rodzajów referencji zewnętrznych. GIT umożliwia oczyszczenie bazy danych z obiektów, które nie są dostępne z zewnątrz przez żaden łańcuch referencji.

Typy obiektów przechowywanych w bazie opsane są poniżej:

Blob

Najprostszy rodzaj obiektu, przechowujący zawartość pliku, bez żadnych dodatkowych danych. W szczególności obiekt taki nie zawiera nazwy pliku.

Drzewo

Drzewa służą do opisu struktury katalogów. Składają się z listy innych drzew oraz blobów. Każdemu elementowi takiej listy jest przypisana nazwa oraz tryb dostępu.

Commit

Obiekty tego typu przechowują historię wersji projektu. Commit składa się z:
  • Referencji do drzewa, zawierającego odpowiadającą mu wersję projektu.

  • Listy referencji do bezpośrednio poprzedzających commitów
    • Lista ta może zawierać więcej niż jeden element, jeśli commit odpowiada połączeniu kilku rozwijanych równolegle wersji w jedną.
  • Komunikatu opisującego zmiany wprowadzone w tej wersji projektu.

  • Nazwiska autora zmian.

  • Nazwiska osoby, która wprowadziła commit do bazy danych.

Tag

Tag zawiera referencję do innego obiektu (zwykle typu commit), nazwę i opis oraz nazwisko osoby, która dodała ów tag do bazy danych. Może również zawierać cyfrowy podpis swojej zawartości. Tagi są zazwyczaj stosowane do oznaczenia wersji projektu, w których zaszła jakaś kluczowa zmiana - np. dodano nową funkcjonalność, zakończono implementację modułu itp. Zwykle oznacza się również wersje projektu udostępnione publicznie.

Referencje

Poza główną bazą danych GIT przechowuje referencje do niektórych obiektów, w postaci plików zawierających sumę kontrolną wskazywanego obiektu. Referencje te możemy podzielić na kilka kategorii.

Gałęzie

Gałąź to nazwany wskaźnik do bieżącej wersji (tz. obiektu typu commit) jednego z wariantów projektu. W najprostszym przypadku mamy tylko jedną, główną gałąź. Często jednak wygodnie jest rozwijać rónolegle kilka wersji projektu - można np. pracować jednocześnie nad dwoma różnymi modułami albo utrzymywać gałąź “stabilną”, w której umieszczany jest tylko przetestowany i kompletny kod.

Gałezie zewnętrzne

W praktycznej pracy z GITem stosuje się zwykle więcej niż jedno repozytorium na projekt (więcej informacji na ten temat mozna znaleźć w dalszej części notatek). Gałąź zewnętrzna to kopia gałęzi z innego repozytorium, wykorzystywana przy synchronizacji zawartości repozytoriów.

Tagi

Referencje do tagów przechowywanych w bazie danych.

Indeks, kopia robocza itp.

Oprócz bazy danych oraz referencji repozytorium GIT może (choć nie musi) zawierać jeszcze dwie części:
  • Kopię roboczą - źródła projektu, pozbawione jakichkolwiek metadanych związanych z zarządzaniem wersjami. Praca nad projektem odbywa się poprzez modyfikowanie kopii roboczej.
  • Indeks - służący do gromadzenia zmian celem umieszczenia ich w bazie danych.

Większość komend systemu GIT zakłada, że bieżący katalog jest kopią roboczą, zaś baza danych, indeks i reszta repozytorium znajdują się w podkatalogu .git. Można to zmienić, ustawiając zmienne środowiskowe GIT_DIR oraz GIT_INDEX.

Wprowadzenie nowej wersji projektu do bazy danych przebiega w trzech krokach:
  1. Kopia robocza jest modyfikowana.
  2. Wybrane zmiany są rejestrowane w indeksie.
  3. Zawartość indeksu jest wprowadzana do bazy.

Korzystanie z GITa

Profil

Pracę z GITem trzeba zacząć od wprowadzenia swojego nazwiska i adresu pocztowego. Dane te są przechowywane w stosownym pliku w katalogu domowym i wykorzystywane do identyfikacji autorów zmian lub etykiet. Dane można wprowadzić za pomocą poniższych poleceń:

$ git config --global user.name “Grzegorz Brzęczyszczykiewicz”
$ git config --global user.email “gb123456@students.mimuw.edu.pl”

Pomijając flagę --global możemy ustawić dane specyficzne dla konkretnego projektu (oczywiście polecenie należy wtedy wydać w odpowiednim katalogu).

Tworzenie repozytorium

Repozytorium GITowe może zostać utworzone na dwa sposoby - jako nowe, puste repozytorium, lub jako kopia istniejącego repozytorium.

Nowe repozytorium

Wydanie polecenia git init spowoduje utworzenie w bieżącym katalogu podkatalogu o nazwie .git. Katalog ten będzie zawierał puste repozytorium. Pliki z bieżącego katalogu nie zostaną automatycznie dodane.

Kopia

Repozytorium może powstać również jako kopia innego repozytorium. W tym celu stosuje się polecenie git clone, jak w poniższym przykładzie:

$ git clone https://gb123456@students.mimuw.edu.pl/git/gb123456

Repozytoria można też klonować za pomocą innych protokołów - w szczególności ssh.

W wyniku wykonania tego polecenia zostanie utworzony katalog gb123456, zawierający repozytorium (w podkatalogu .git) oraz kopię roboczą zgodną ze stanem gałęzi master klonowanego projektu. Katalog docelowy oraz nazwę gałęzi można zmienić odpowiednimi opcjami git clone. Zostaną również utworzone referencje zewnętrzne, odpowiadające gałęziom kopiowanego repozytorium.

Uwaga

Warto zauważyć, że git clone tworzy kopię całego repozytorium, czyli wszystkich wersji projektu wraz z całą historią zmian.

Czasami pożadane jest utworzenie kopii repozytorium bez indeksu czy kopii roboczej. Taki klon jest zwykle umieszczany na osobnej maszynie i służy za głowne repozytorium, z którym synchronizują się wszyscy członkowie zespołu. Opcja --bare sprawia, że polecenia git clone i git init nie tworzą indeksu ani kopii roboczej.

Zazwyczaj po sklonowaniu projektu chcemy mieć możliwość wprowadzenia naszych zmian do oryginalnego repozytorium i/lub pobrania wersji, które w międzyczasie zostały tam umieszczone. Służą do tego komendy fetch, push i pull, omówione w dalszej częsci notatek.

Wprowadzanie danych do repozytrium

Aby umieścić nową wersję pliku (albo po prostu nowy plik) w repozytorium, trzeba ją najpierw wprowadzić do indeksu. Służy do tego komenda git add. Za pomocą komendy git status możemy stwierdzić, które zmiany w kopii roboczej zostały wprowadzone do indeksu:

$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   lab05.rst
#
no changes added to commit (use "git add" and/or "git commit -a")

W powyższym przykładzie mamy jeden zmieniony plik, który nie został dodany do indeksu.

$ git-add lab05.rst
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   lab05.rst
#

Teraz zmiany są gotowe do umieszczenia w bazie. Komenda git commit wprowadza zawartość indeksu do repozytorium. Trzeba jej podać treść komunikatu opisującego wprowadzone zmiany (opcja -m).

$ git commit -m "Initial version of GIT notes."
[master 9a7c7bf] Initial version of GIT notes.
 1 files changed, 149 insertions(+), 3 deletions(-)
 rewrite lab05.rst (100%)

GIT zawiera komendy umożliwiające zarządzanie zawartością indeksu, w szczególności usuwanie omyłkowo dodanych wersji.

Czasami zmiana polega na usunięci pliku. Można to zrobić komendą git rm, która wprowadzi stosowne informacje do indeksu i usunie plik z kopii roboczej:

$ git rm test.txt
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    test.txt

W podobny sposób możemy prznieść plik, lub zmienić jego nazwę, komendą git mv

$ git mv test.txt testfile.txt
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    test.txt -> testfile.txt
#

Ostrzeżenie

GIT nie przechowuje żadnych informacji o operacjach kopiowania bądź przeniesienia pliku. Komenda git status i podobne muszą za każdym razem wykrywać kopiowanie na podstawie identycznośći (bądź podobieństwa) obiektów.

W przypadku omyłkowego wprowadzenia do bazy niepoprawnych danych można się posłużyć komendą git commit z opcją --amend. Wówczas nowo wprowadzona wersja zastąpi poprzedni commit - nowy commit będzie miał taką samą listę poprzedników, jak ten zastąpiony i będzie wskazywany przez bieżącą gałąź.

Ostrzeżenie

Poprawki z wykorzystaniem opcji --amend mogą powodować problemy, jeśli w jakimś klonie repozytorium zostały już wprowadzone dalsze zmiany.

Przeglądanie repozytorium

git show

Zawartość dowolnego obiektu w repozytorium możemy wyświelić za pomocą komendy git show. Obiekt do wyświetlenia możemy wskazać na kilka sposobów
  • Podając sumę kontrolną. Możemy poprzestać na dowolnym prefiksie, który jest uniklany w ramach przeglądanego repozytorium. Zwykle około 6 znaków wystarczy.
  • Podając nazwę gałęzi lub etykiety.
  • Ścieżką do pliku (oraz wskaźnikiem do wersji).
  • Opisem ścieżki przechodzącej po referencjach do poprzednich commitów. Na przykład e456321^2 to drugi poprzednik obiektu commit o sumie kontrolnej zaczynającej się na e456321, zaś e456321~7 to ścieżka cofajaća się o siedem obiektów od tego commita (zawsze wybierając pierwszy z listy poprzedników).
  • Do drzewa możemy odwołać się przez wskazanie commita i dodanie sufiksu ^{tree}.

git show - przykłady

Podanie obiektu typu commit powoduje wyświetlenie informacji o zmianie oraz różnic w stosunku do poprzedniej wersji (w formacie diff).

$ git show master
commit b05d38eb29ce921c871f84caf9859849033ea2c6
Author: Tadeusz Sznuk <tsznuk@mimuw.edu.pl>
Date:   Mon Mar 12 00:14:15 2012 +0100

    Description of 'stash' and 'log' commands.

diff --git a/lab05.rst b/lab05.rst
index b818615..bee1b6c 100644
--- a/lab05.rst
+++ b/lab05.rst
...
...

Możemy też wyświetlić drzewo

$ git show master^{tree}
tree master^{tree}

Makefile
_build/
_static/
_templates/
conf.py
gdb_lexer/
index.rst
lab01.rst
lab02.rst
lab03.rst
lab04.rst
lab05.rst
lab06.rst
lab07.rst
lab08.rst
lab09.rst
lab10.rst
lab11.rst
lab12.rst
lab13.rst
lab14.rst
lab15.rst

Możemy przyjrzeć się zawartości pliku w jednej ze starszych wersji (tutaj opisanej bezpośrednio przez sumę kontrolną):

$ git show 95faba47:lab05.rst
Lab 5
======
Chwilowo nic tu nie ma.

Ten sam efekt uzyskamy cofajać się o kilka wersji do tyłu:

$ git show master~5:lab05.rst
Lab 5
======
Chwilowo nic tu nie ma.

Jak widać, w nowszej wersji plik wygląda nieco inaczej:

$ git show master:lab05.rst
Lab 5 - GIT
============

Wtęp
-----
...
...

git log

Jedną z bardziej pożytecznych funkcji systemu kontroli wersji jest możliwość przeglądania historii zmian danego pliku lub plików. Komenda git log pozwala wyświetlić kolejne commity, które zmieniały zawartość wskazanych plików:

$ git log lab04.rst
commit 9524f0f5c8be7ce791e1ca39ce313984bbf6a163
Author: Tadeusz Sznuk <tsznuk@mimuw.edu.pl>
Date:   Mon Mar 5 15:52:53 2012 +0100

    Some fixes in lab04.

commit 95faba478612316425101d616de4c9878b4cdd7b
Author: Tadeusz Sznuk <tsznuk@kalafior.(none)>
Date:   Mon Mar 5 11:23:25 2012 +0100

    Minor additions in lab04.

commit 0cbae9692b7f2a74cc73d9270ff7c887fc70169b
Author: Tadeusz Sznuk <tsznuk@mimuw.edu.pl>
Date:   Mon Mar 5 00:54:12 2012 +0100

    Lab 4 (incomplete) + GDB lexer.

git diff

Komenda git diff pozwala porównać dwa pliki lub katalogi przechowywane w repozytorium. W szczególności może porównać dwie wersje tego samego pliku i wyświetlić zmiany. Może również porównać zawartość kopii roboczej z indeksem. Poniższy przykład ilustruje oba te przypadki.

$ git diff
diff --git a/lab05.rst b/lab05.rst
index 55840fd..e72d221 100644
--- a/lab05.rst
+++ b/lab05.rst
@@ -318,7 +318,7 @@ Jedną z bardziej pożytecznych funkcji systemu kontroli wersji jest możliwoś

 git diff
 ^^^^^^^^^
-Komenda ``git diff`` pozwala porównać dwa pliki lub katalogi przechowywane w repoztorium. W szczególności może porównać dwie wersje tego samego pliku i wyświetlić zmiany:
+Komenda ``git diff`` pozwala porównać dwa pliki lub katalogi przechowywane w repozytorium. W szczególności może porównać dwie wersje tego samego pliku i wyświetlić zmiany:

$ git add lab05.rst
$ git commit -m "Fixed a typo."
$ git diff master:lab05.rst master~1:lab05.rst
diff --git a/master:lab05.rst b/master~1:lab05.rst
index e72d221..55840fd 100644
--- a/master:lab05.rst
+++ b/master~1:lab05.rst
@@ -318,7 +318,7 @@ Jedną z bardziej pożytecznych funkcji systemu kontroli wersji jest możliwoś

 git diff
 ^^^^^^^^^
-Komenda ``git diff`` pozwala porównać dwa pliki lub katalogi przechowywane w repoztorium. W szczególności może porównać dwie wersje tego samego pliku i wyświetlić zmiany:
+Komenda ``git diff`` pozwala porównać dwa pliki lub katalogi przechowywane w repozytorium. W szczególności może porównać dwie wersje tego samego pliku i wyświetlić zmiany:

Oczywiście możemy cofnąć się w historii o więcej niż jeden krok, albo porównywać pliki z różnych gałęzi.

$ git diff master:conf.py green_theme:conf.py
diff --git a/master:conf.py b/green_theme:conf.py
index 70dd393..3ab6640 100644
--- a/master:conf.py
+++ b/green_theme:conf.py
@@ -96,7 +96,7 @@ mathjax_path = "/~tsznuk/mathjax/MathJax.js?config=default"

 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'sphinxdoc'
+html_theme = 'nature'

 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the

Todo

git grep, gitk, git instaweb.

Etykiety

Nową etykietę można utworzyć poleceniem git tag, jak w poniższym przykładzie.

$ git tag -a v1.0 -m ‘First public release.’

Jeśli pominiemy flagę -a, GIT utworzy etykietę jako referencję bezpośrednio do biektu typu commit - do bazy nie zostanie dodany obiekt tag. Nie będzie też możliwe podanie komentarza ani podpisu (opcje -s i -u).

Zarządzanie gałęziami

git branch

Nową gałąź tworzy się poleceniem git branch <nazwa_gałęzi>. Domyślnie gałąź będzie wskazywać na bieżącą wersję projektu. Należy zauważyć, że git branch nie zmienia aktywnej gałęzi i nie powoduje żadnych modyfikacji w kopii roboczej.

git checkout

Aby zmienić aktywną gałąź (i zarazem zawartość kopii roboczej) należy użyć komendy git checkout <nazwa_gałęzi>. Jeśli podamy opcję -b, zostanie utworzona i aktywowana nowa gałąź. Zatem polecenie git checkout -b <nazwa_gałęzi> jest równoważne git branch <nazwa_gałęzi> ; git checkout <nazwa_gałęzi>.

Gałęzi możemy wylistować komendą git branch bez żadnych argumentów:

$ git branch
  green_theme
* master

Aktywna gałąź jest oznaczona gwiazdką.

git merge

Zmiany wykonane w dowolnej gałęzi możemy połączyć z bieżącą gałęzią, korzystając z komendy git merge. Ilustruje to poniższy przykład.

$ git merge green_theme
Merge made by the 'recursive' strategy.
 conf.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Po połączeniu czasami nie chcemy już dalej rozwijać drugiej gałęzi. Możemy ją usunać komendą git branch -d.

$ git branch -d green_theme
Deleted branch green_theme (was d73b056).

Konflikty

Niestety w praktyce (oraz w zadaniach zaliczeniowych z IPP) zdarza się, że zmian dokonanych w jednej gałęzi nie można w oczywisty sposób połączyć z tymi z innej. W takim przypadku GIT poinformuje użytkownika o konieczności ręcznego uzgodnienia zmian i wskaże modyfikacje powodujące konflikt.

Załóżmy, że w projekcie utworzyliśmy nową gałąź i w trakcie pracy przestawiliśmy w niej jakąś opcję w pliku konfiguracyjnym:

$ git checkout -b temp_brnach
$ vim conf.py
$ git add conf.py
$ git commit -m "Disabled sphinx signature in page footer."
[temp_branch cbd5882] Disabled sphinx signature in page footer.
 1 files changed, 1 insertions(+), 1 deletions(-)

Potem wróciliśmy do gałęzi głównej i tam również zmienliśmy konfigurację, ale w przeciwny sposób:

$ git checkout master
$ vim conf.py
$ git add conf.py
$ git commit -m "Explicitly enabled sphinx signature in page footer."
[master 61d2e24] Explicitly enabled sphinx signature in page footer.
 1 files changed, 1 insertions(+), 1 deletions(-)

Jeśli teraz zechcemy scalić naszą tymczasową gałąź (ze względu na jakieś inne zmiany w niej), GIT wykryhe konflikt:

$ git merge temp_branch
Auto-merging conf.py
CONFLICT (content): Merge conflict in conf.py
Automatic merge failed; fix conflicts and then commit the result.

W treści pliku conf.py możemy teraz znaleźć taki fragment:

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
<<<<<<< HEAD
html_show_sphinx = True
=======
html_show_sphinx = False
>>>>>>> temp_branch

Widać tutaj, jakie zmiany zaszły w obu łaczonych gałęziach. Teraz należy poprawić plik (usuwając jedną z wersji albo np. łączac oba warianty) i umieścić wynik w repozytorium:

$ vim conf.py
$ git add conf.py
$ git commit -m "Resolved conflict in conf.py."
[master 5529716] Resolved conflict in conf.py.

git stash

Czasami chcielibyśmy wprowadzić jakieś modyfikacje w innej gałęzi bez utraty zmian wprowadzonych w kopii roboczej. W tym celu musimy gdzieś zachować bieżące zmiany przed cofnięciem ich. Służy do tego komenda git stash.

$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 14 commits.
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   lab05.rst
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git stash
Saved working directory and index state WIP on master: 5511417 Reverted theme ch
anges.
HEAD is now at 5511417 Reverted theme changes.

Po wykonaniu tej komendy kopia robocza jest zgodna z ostatnią wersją bieżącej gałęzi

$ git status # On branch master # Your branch is ahead of ‘origin/master’ by 14 commits. # nothing to commit (working directory clean)

Zapisane zmiany można przywrócić komendą git stash apply.

$ git stash apply stash@{1}
# On branch master
# Your branch is ahead of 'origin/master' by 14 commits.
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   lab05.rst
#
no changes added to commit (use "git add" and/or "git commit -a")

Argumentem jest identyfikator zestawu zmian. Można utworzyć wiele takich zestawów (używając wielokrotnie git stash), przeglądać je za pomocą komend git stash list i git stash show. Dodatkowo identyfikator zapisanej kopii roboczej można podać jako argument do komendy git diff i podobnych.

Usuwanie zmian

Todo

git reset.

Synchronizacja

Zazwyczaj przy pracy z systemem GIT wykorzystywane jest więcej niż jedno repozytorium. W najprostszym modelu każdy członek zespołu (niekiedy jednoosobowego) ma własne repozytorium na swojej maszynie, a dodatkowo istnieje główne repozytorium umieszczone na serwerze. Możliwe są też bardziej wymyślne modele pracy - GIT jest bardzo elastyczny pod tym względem. Tworzenie kopii repozytorium za pomocą komendy git clone zostało już omówione. Po sklonowaniu trzeba jednak w jakiś sposób wprowadzić nasze zmiany z powrotem na serwer. Trzeba też pobierać zmiany wprowadzone przez innych (albo nas samych, ale na innej maszynie). Służa do tego komendy git fetch, git pull i git push.

git fetch

Komenda git fetch pobiera ze zdalnego repozytorium nowe obiekty i uaktualnia zdalne gałęzi. Nie próbuje jednak scalić zmian z bieżącym stanem naszego repozytorium. Zostanie zaktualizowana np. gałąź zdalna origin/master, ale już nie master. Scalenia można dokonać komendą git merge (w tym przypadku pisząc git merge origin/master i rozwiązując ewentualne konflikty).

git pull

Komenda git pull działa podobnie do git fetch, ale po zsynchronizowaniu gałęzi zdalnych scala je z lokalnymi. Inaczej mówiąc, stanowi połaczenie git fetch z git merge.

$ git pull
remote: Counting objects: 48, done.
remote: Compressing objects: 100% (44/44), done.
remote: Total 45 (delta 29), reused 0 (delta 0)
Unpacking objects: 100% (45/45), done.
From /home/dokstud/tsznuk/ipp
   9524f0f..9113ef9  master     -> origin/master
Merge made by recursive.
 conf.py   |    2 +-
 lab05.rst |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 570 insertions(+), 4 deletions(-)

git push

Zmiany z lokalnego repozytorium można przesłać do zdalnego za pomocą komendy git push. Powiedzie się ona tylko, jeśli repozytorium jest aktualne - gałęzi lokalne są zsynchronizowane ze zdalnymi i od czasu synchronizacji nie zaszły żadne zmiany w zdalnym repozytorium. W przeciwnym wypadku GIT zgłosi błąd:

$ git push
To /home/dokstud/tsznuk/ipp.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to '/home/dokstud/tsznuk/ipp.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

Jeśli nasze repozytorium będzie aktualne, wynik będzie taki:

$ git push
Counting objects: 45, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (41/41), done.
Writing objects: 100% (42/42), 11.90 KiB, done.
Total 42 (delta 28), reused 0 (delta 0)
To ssh://tsznuk@duch.mimuw.edu.pl/home/dokstud/tsznuk/ipp.git
   9524f0f..0a5fd4c  master -> master

Kilka uwag odnośnie korzytania z VCS

Przy korzystaniu z jakiegokolwiek systemu kontroli wersji warto pamiętać o poniższych uwagach:
  • Commit należy robić często i unikać gromadzenia kodu na lokalnej maszynie (ale z uwględnieniem następnych uwag).
  • Każdy zestaw zmian (commit) umieszczony w repozytorium powinien dotyczyć tylko jednej kwestii - nie należy łączyć zmian, które nie są ze sobą związane. W szczególności każdorazowe umieszczanie w repozytorium wszystkich zmodyfikowanych w danej chwili plików jest zazwyczaj złym pomysłem.
  • Commit powinien być w miarę możliwości kompletny - należy unikać wysyłania kodu do repozytrium tylko dlatego, że jest piątek i trzeba umieścić pracę na serwerze przed pójściem do domu.
  • Potrzebna jest rozsądna polityka korzystania z gałęzi - np. częśto przydaje się gałąź stabilna, która przechodzi wszystkie testy i można jej zawartość wysłać do klientów. Oczywiście czasem trzeba do takiej gałęzi przenieść niektóre poprawki z gałęzi głównej.
  • Warto też stosować etykiety - zwłaszcza w dłuższych projektach, przed scaleniem większych gałęzi itp.
  • Zwykle w repozytorium umieszcza się tylko pliki źródłowe, a unika wstawiania tam czegokolwiek, co może zostać z nich wygenerowane. Od tej zasady niekiedy robi się wyjątki - np. można dodać do repozytorium binarną wersję jakiejś biblioteki, której kompilacja jest skomplikowana i wymaga dodatkowych narzędzi.