Introducció

Avui en dia tothom espera que facis servir un sistema de gestió de control de versions, que acostumbra a ser git.

Per això les IDEs ja no s'encarreguen de recuperar fitxers borrats, o versions anteriors d’un fitxer perquè donen per suposat que estas fent servir git.

Però tu fas servir git? Més aviat no.

En aquesta activitat a més de mostrar el codi també fem servir gràfics creats amb Mermaid.

Primers passos

Configura git:

$ git config --global init.defaultBranch main

Crea un directori test per començar a treballar i entra en ell:

```sh
$ mkdir test
$ cd test

Crea un fitxer hola.md, escriu alguna cosa en ell i borra el fitxer:

$ echo "Hola" > hola.md
$ ls
$ rm hola.md 
$ ls

Et pot semblar un exercici una mica ximple, però borrar el que no toca acostuma a passar i no és gens divertit.

Aquest cop anem a versionar el directori amb git:

$ git init
$ echo "Hola" > hola.md
$ ls
$ rm hola.md
$ ls

Com pots verificar hem tornat a perdre el fitxer perquè Git només guarda aquells fitxers que li han dit que guardi!

Tornem a començar, però aquest cop preguntem a git:

$ echo "Hola" > hola.md
$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    	hola.md

Pots veure que git sap que el fitxer hola.md està en la carpeta, i t’avisa que no l’està controlant.

Si vols que controli el fitxer has de dir a git que ho faci amb la comanda git add:

$ git add hola.md
$ git status
Changes to be committed:
    	new file:   hola.md

Perfecte, ara borrem el fitxer i llestos

$ rm hola.md
$ ls

Doncs el fitxer s’ha borrat

I que ha fet git al respecte?

$ git status
Changes to be committed:
    	new file:   hola.md
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    	deleted:	hola.md

Doncs saps que li havies dit que controles el fitxer hola.md i que l’has borrat

Git et dona dues opcions:

  1. Que s’oblidi del fitxer → git rm hola.md
  2. Que restauri el fitxer → git restore hola.md

En aquest cas el que volem es recuperar el fitxer:

$ git restore hola.md

Si has borrat el fitxer com es que git el pot recuperar? Doncs perquè quan vas fer git add hola.md es va guardar una còpia en la carpeta .git

Si fas un ls -a pots veure la carpeta oculta que vas crear abans amb la comanda git init.

$ ls -a
.  ..  .git  hola.md

Modifica el fitxer hola.md i mira que passa quan fas git status:

$ echo "Adeu" > hola.md
$ git status
Changes to be committed:
        new file:   hola.md
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   hola.md

Git té una còpia del fitxer hola.md que fas afegir quan vas fer git add, i tambè sap que no es correspon al fitxer actual (algú l’ha modificat).

Commit

Però el que fa més interessant a un sistema de control de versions es que pots anar guardant els canvis un radera l’altre i tornar enrere quan vulguis.

Si vols guardar els canvis de forma permanent has de fer un commit:

$ git commit -m "He afegit el fitxer hola.md"
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.

I no et deixen fer un commit! Per fer un commit has de configurar el teu nom i correu electrònic perquè quedi constància de qui ha fet què. I a qui li interessa això si jo ja se qui sóc?

Doncs perquè git crea el que es coneix com un repositori que es pot compartir de manera col.laborativa amb altre gent i ha de quedar constància de qui ha fet què.

Configura el teu nom i correu electrònic:

$ git config --global user.email "ddemingo@xtec.cat""
$ git config --global user.name "David de Mingo"

Ajuda pel professor. Per verificar que l’alumne ha fet el que havia de fer executa aquesta comanda:

$ git config --list
init.defaultbranch=main
user.email=ddemingo@xtec.cat
user.name=David de Mingo
...

I ja pots fer un commit:

$ git commit -m "He afegit el fitxer hola.md"
[main (root-commit) 701f544] He afegit el fitxer hola.md
 1 file changed, 1 insertion(+)
 create mode 100644 hola.md

Si demanes a git que et mostri el log pots veure que David de Mingo ha afegit el fitxer hola.md al repositori.

$ git log
Author: David de Mingo <ddemingo@xtec.cat>
Date:   Mon Mar 27 20:13:38 2023 +0000
    He afegit el fitxer hola.md
gitGraph
    commit id:"eae4959a"

Suposo que encara no saps exactament de que va tot això i ho trobes poc interessant

Doncs anem a fer uns quants commits

$ echo "Dilluns" > hola.md
$ git add hola.md
$ git commit -m "Ara es dilluns"
$ echo "Dimarts" > hola.md
$ git add hola.md
$ git commit -m "Ara es dimarts"

Si fas git log pots veure totes les modificacions que s’han guardat:

$ git log
commit eae4959af03021666dabccdc4be0074335827e3d (HEAD -> main)
    Ara es dimarts
commit 3173dfd5b859ce0c93c15ba2d6a9d1efad874907
    Ara es dilluns
commit 701f544964f4a89874b6905397e1ec188bb07dda
    He afegit el fitxer hola.md
gitGraph
    commit id:"701f5449"
    commit id:"3173dfd5"
    commit id:"eae4959a"

Checkout

Cada modificació (commit) tè un identificador únic tal com pots veure a la sortida de la comanda git log.

Aquest identificador és un hash criptogràfic (Criptografia)

Que haig de fer per poder veure les diferents versions del fitxer hola? Demanar a git que restauri la versió que tu vols amb la comanda checkout:

$ git checkout 701f
$ cat hola.md
Hola
$ git checkout 3173
$ cat hola.md
Dilluns

Pots veure que no cal que escriguis tot l’identificador, amb els primers dígits és suficient

I per tornar a la versió més actual pots fer servir l’identificador del commit o el de la branca (en parlem després):

$ git checkout main
$ cat hola.md
Dimarts

Tag

Això dels identificadors està molt bé pels ordinadors, però les persones fem servir noms perquè és més fàcil per nosaltres. T’enrecordes de memòria d’algun número de telèfon?

Git permet etiquetar commits amb l’etiqueta que nosaltres vulguem.

Per exemple, podem etiquetar el commit actual amb l’etiqueta dimarts

$ git tag dimarts

I podem etiquetar el commit “Ara és dilluns” amb l’etiqueta dilluns (aquest cop haig d’indicar la id del commit)

$ git tag dilluns 3173

Pots veure que tenim dos etiquetes:

$ git tag
dilluns
dimarts

I puc canviar de versió fent checkout del tag:

$ git checkout dilluns
Previous HEAD position was eae4959 Ara es dimarts
HEAD is now at 3173dfd Ara es dilluns

I torna a l’altre:

$ git checkout dimarts
Previous HEAD position was 3173dfd Ara es dilluns
HEAD is now at eae4959 Ara es dimarts

També pots borrar etiquetes:

$ git tag -d dilluns
$ git tag
dimarts

Ignore

Potser et sorpendra, però git només el fan servir els programadors

I els programdors escribim codi que s’ha de compilar. I que vol dir compilar? Donc que es creen nous fitxers i executables, que necessitem llibreries, etc. i que naturalment no s’han versionar!

I com pot saber git que s’ha de versionar i que no s’ha de versionar? Doncs no tè ni idea, és la teva feina!

Per això has de dir explicitamente quins fitxers ha de controlar amb git add. Però tambè has de saber que un bon programador sempre troba la manera de fer menys per aconseguir més. Per això es van afegir la opció git add --all.

Crea dos fitxers i fes un git add –-all:

$ echo "Lluna blava" > lluna.md
$ echo "Mar vermell" > mar.md
$ git add --all 

Però si afegim tot, també afegim el que no s’ha d’afegir.

Podem crear un fitxer .gitignore on indicarem tots els fitxers i carpetes que git sempre ha d’ignorar.

Per exemple, no volem versionar els fitxers txt:

$  echo "*.txt" > .gitignore
$ echo "Terra groga" > terra.md
$ echo "Llac blanc" > llac.txt

Si executes git status pots veure que el fitxer llac.txt no s’ha afegit a la llista de fitxers que git ha de controlar, perquè el fitxer .gitignore diu que ha d’ignorar tots els fitxers que acabin amb .txt.

Branques

I ara comencem una sessió de jardineria!

Quan fas un projecte de programació, quan fas un examen de programació, mai et surt res a la primera. Vas fent, t’equivoques, tornes enrera (has de desfer coses), intentes coses noves, etc., i tot és un galimaties. La programació es així, i la majoria de les tasques de la teva vida diària són així.

Per poder treballar en condicions sempre has de poder avançar desde una posició segura a una altre posició segura. I més important, poder tornar a una posició segura en que tot funciona. Per això git permet crear branques de treball.

Branch

Crear una branca és molt fàcil:

$ git branch test
$ git branch
* main
  prova

Ara mateix les dues branques (main es una branca com qualsevol altre) són iguals perquè les dos estan apuntant al mateix commit.

El que anem a fer ara és canvia a la branca prova i fer un commit:

$ git checkout test
Switched to branch 'test'

Pots veure que canviar de branca és fer un checkout.

Ara ja podem crear un fitxer i fer un commit:

$ echo 'print("hola david!")' > hello.py
$ git add hello.py
$ git commit -m "He creat el fitxer hello.py"
[test 00e7a94] He creat el fitxer hello.py
 1 file changed, 1 insertion(+)
 create mode 100644 hello.py

Si tornem a la branca main pots veure que tot els commit nous de la branca test no apareixen. Per tant el fitxer hello.py no existeix:

$ git checkout main
Switched to branch 'main'
$ python3 hello.py
python3: can't open file '/home/box/test/hello.py': [Errno 2] No such file or directory

Si volem borrar la branca test, git ens adverteix de que no és convenient perquè tots els commits nous de la branca test es perdran.

$ git branch -d test
error: The branch 'test' is not fully merged.
If you are sure you want to delete it, run 'git branch -D test'.

De totes maneres, perquè voldria borrar la branca test? Doncs perquè un projecte només té un objectiu:

  1. Al final tot el que funciona ha d’acabar a la branca principal
  2. I el que no ha funcionat i és un disbarat s’ha d’eliminar.

Merge

Si el que he fet en la branca test està bé i funcional (no acostuma a passar), puc fusionar els canvis a la branca principal:

$ git merge test
Updating 80ea360..00e7a94
Fast-forward
 hello.py | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 hello.py

Ara ja tens el fitxer hello.py a la branca principal:

$ python3 hello.py
hola david!

I pots borrar la branca test:

$ git branch -d test
Deleted branch test (was 00e7a94).

De totes maneres molts alumnes no veuen la necessitat de crear una branca per una cosa tant simple.

Doncs anem a fer una activitat ben divertida (almenys pel profe 🙄).

Activitat

  1. Crea una carpeta nova on estarà el teu petit projecte python i versiona la carpeta

  2. Crea un fitxer python main.py que faci alguna cosa i fes un commit del nou fitxer.

  3. Descarrega una llibreria amb pip (per exemple numpy) i fes la servir en main.py. Configura git perquè ignori els fitxers descarregats (si fos el cas) i fes un nou commit.

  4. Crea una nova branca dev, canvia de branca, afegeix noves funcions a main.py i fes un commit.

  5. Torna a la branca main i fes un merge de la branca dev.

  6. Fes un checkout del primer commit i verifica que es la primera versió de main.py.

  7. Torna a l’últim commit i fes un tag v1

  8. Modifica `main.pyp i fes un altre commit.

  9. Fes un git log per veure tot l’historial