Git tutorial - part 2

Acest tutorial e mai mult pentru colegii de grupă cu care voi lucra la Proiect Colectiv

Prima parte am scris-o mai demult, dar nu îi bai, că nu s-o schimbat multe la Git de atunci :)))

În prima parte am configurat Git-ul, am creat un proiect nou, cu un fișier .gitignore și am făcut primul commit. În cei doi ani care au trecut de atunci ne-am dat seama că la primul commit am greșit două chestii: mai trebuia inclus fișierul config.txt și trebuia să dăm un mesaj de commit mai detaliat.

> git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#   config.txt nothing added to commit but untracked files present (use "git add" to track)
> git add config.txt
> git commit --amend -m "First commit including config file and vital text information" ...
> git status # On branch master nothing to commit, working directory clean`

Acum să vedem cum revenim la versiuni anterioare ale fișierelor. Sunt 3 situații distincte. Primele două se referă la schimbări făcute de la ultimul commit încoace, iar a 3a este când vrem să revenim la un commit anterior.

În primul caz fișierul nostru este urmărit de Git, dar mod­i­ficările noi nu le-am adăugat încă (nu am dat git add). În acest caz un git checkout ne rezolva problema.

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

> git checkout -- release.txt
> git status
# On branch master
# nothing to commit, working directory clean

În al doilea caz, i-am dat add la fișierul schimbat, dar nu am dat încă commit. Aici ne folosim de git reset.

> echo something >> release.txt
> git add release.txt
> git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
# #   modified:   release.txt
#
> git reset HEAD release.txt
Unstaged changes after reset:
M release.txt
> 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: release.txt
#
# no changes added to commit (use "git add" and/or "git commit -a")

Și cu asta am redus problema la cazul anterior :)))

În al treilea caz, dacă vrem să revenim la o variantă de pe un branch anterior, folosim tot reset, dar nu pe HEAD ci pe commitul la care vrem să revenim.

> echo something >> release.txt
> git commit -a -m "Add important stuff to release"
> git status
# On branch master nothing to commit, working directory clean
> cat release.txt something
> git log
commit 9fa9fb6471797f05e703229c02549eac2ada763e Author: Roland  Date:   Sun Mar 3 22:34:25 2013 +0200

 Add important stuff to release

  commit f061583219bb746507f17a31f2d8ae154a342e06
 Author: Roland <rolisz@yahoo.com>
 Date: Sun Mar 3 21:27:35 2013 +0200

 First commit including config file and vital text information
> git reset --hard f06158
 HEAD is now at f061583 First commit including config file and vital
 text information
> cat release.txt

Id-ul commitului la care vrem să mergem înapoi îl aflăm cu comanda git log și apoi primele câteva caractere din id îl dăm la git reset.

Și acum să trecem la copăcei. Errr branches. Să zicem că în timp ce lucrăm la ceva feature, ne vine o idee super-șmenoasă despre un alt feature și ne grăbim să o im­ple­men­tăm până nu o uităm. Branch-urile ne permit să avem variante diferite ale codului în paralel, pe care apoi le putem combina la sfârșit.

> echo feature1 > release.txt
> git commit -a -m "Work on feature 1"`

> git checkout -b feat2
> git status
# On branch feat2
# nothing to commit, working directory clean
> echo feature2 >> release.txt
> git commit -a -m
> cat release.txt
feature1
feature2
> git checkout master
> cat release.txt
feature1

Acum avem două branchuri care au conținut diferit pentru fișierul release.txt. Să zicem că restul echipei se uită peste codul din feat2 și e ok și vrem să le unim. Doar că noi între timp pe master am adăugat ceva la release.txt. Și va trebui să rezolvăm conflictul.

> echo feature3 >> release.txt
> git merge feat2
# Auto-merging release.txt
# CONFLICT (content):
#  Merge conflict in release.txt
#  Automatic merge failed; fix conflicts and then commit the result.
> cat release.txt
feature1
<<<<<<< HEAD
feature3
=======
feature2
>>>>>>>
feat2

Ce îi chestia aia din fișierul nostru? Git nu știe cum să îmbine cele două versiuni, așa că le-a băgat pe amândouă, iar noi trebuie să alegem ce ne trebuie și apoi facem commitul. În cazul nostru vom păstra ambele chestii, dar deobicei se păstrează doar una din ele, cealaltă ștergându-se.

// edit release.txt
> git add release.txt
> git commit -m "Add feat2"
> cat release.txt
feature1
feature3
feature2

Dacă nu ar fi fost conflictul între cele două featureuri, merge-ul s-ar fi făcut automat.

Asta ar fi partea a doua a tu­to­ri­alu­lui. Pentru cei care au fost intimidați de linia de comandă, recomand http://code.google.com/p/gi­tex­ten­sions/ sau Github for Windows. Toate operațiile pe care le-am descris aici au echiva­len­turi click-click în aceste programe.

Posibil să mai urmeze o parte a 3a (sper că nu peste 2 ani iarăși :D), cu workflow între mai multe persoane cu GitHub.