La v0.19 funciona i aguanta els errors, però per arribar-hi has tocat magatzem.py, model.py, interficie.py i __main__.py alhora. Si demà descobreixes que la validació de dies trenca alguna cosa, com tornes enrere? I com saps exactament què vas canviar dimarts? La resposta que fa servir tothom des de fa vint anys és Git: un sistema que desa la història completa del projecte, permet tornar a qualsevol punt anterior, deixa provar idees sense por i fa possible que diverses persones treballin sobre el mateix codi sense trepitjar-se. Aquesta lliçó t'ensenya Git des de zero: el model mental de les tres zones, les comandes del dia a dia, com s'escriu un bon missatge de commit, què no es versiona mai, com s'obren i es fusionen branques —i com es resol un conflicte sense pànic—, com es desfà el que s'ha fet i què són GitHub i GitLab. Al final, TascaFàcil viurà en un repositori amb el seu historial.

Contingut

  1. El problema: projecte_final_v3_bo_definitiu
  2. Instal·lar i configurar Git
  3. El model mental: tres zones
  4. Les comandes del dia a dia
  5. Què és un commit i com s'escriu el seu missatge
  6. .gitignore: el que mai no es versiona
  7. Branques: treballar sense por
  8. Conflictes: què són i com es resolen
  9. Desfer: restore, revert i reset
  10. Remots: GitHub, GitLab i els pull requests
  11. Etiquetes i versionatge
  12. TascaFàcil v0.20: el projecte sota Git
  13. Errors habituals i consells
  14. Exercicis
  15. Conclusió

  1. El problema: projecte_final_v3_bo_definitiu

Tothom ha viscut aquesta escena: una carpeta amb informe.docx, informe_v2.docx, informe_v2_revisat.docx, informe_final.docx i informe_final_BO.docx. Amb codi és pitjor, perquè a més cal saber quina línia va canviar entre dues versions i per què. Copiar carpetes falla en tot: ocupa espai, no diu què ha canviat, no explica el motiu, no permet barrejar la feina de dues persones i no hi ha manera de recuperar només una part.

Un sistema de control de versions (VCS) resol exactament això: desa instantànies del projecte amb la seva data, el seu autor i una explicació, i permet comparar, tornar enrere i combinar canvis. Hi ha dues famílies. Els centralitzats (Subversion, CVS) desen la història en un únic servidor: sense connexió no es pot treballar i si el servidor cau, s'ha acabat. Els distribuïts (Git, Mercurial) donen a cada persona una còpia completa de l'historial al seu propi ordinador: es treballa sense connexió, cada clon és una còpia de seguretat i només se sincronitza amb el servidor quan convé. Git, creat el 2005 per al desenvolupament de Linux, és avui l'estàndard absolut.

  1. Instal·lar i configurar Git

Git es descarrega de git-scm.com (a Linux sol venir instal·lat o s'instal·la amb el gestor de paquets). Per comprovar-ho i configurar-lo, tres ordres que només s'executen una vegada per ordinador:

git --version                                     # comprova que esta installat
git config --global user.name "Marta Ruiz"        # qui signa els commits
git config --global user.email "[email protected]"
git config --global init.defaultBranch main       # nom de la branca inicial
git config --list                                 # veure tota la configuracio

El nom i el correu no són un tràmit: queden gravats per sempre a cada commit que facis, i són el que apareix quan algú pregunta qui va tocar una línia. L'opció --global els aplica a tots els teus projectes; sense ella, només al repositori actual, que és el que es fa servir quan el correu de la feina i el personal s'han de separar.

  1. El model mental: tres zones

Aquesta és la part que més costa al principi, i tot s'aclareix si entens que un canvi passa per tres zones abans de quedar desat a la història:

  • Directori de treball: els teus fitxers tal com són ara al disc.
  • Zona de preparació (staging area o index): la llista de canvis que vols incloure al commit següent. És el gran encert de Git: et deixa triar què hi entra i què no.
  • Repositori: la carpeta .git, on viuen tots els commits ja confirmats.
flowchart LR
    A[Directori de treball] -->|git add| B[Zona de preparacio]
    B -->|git commit| C[Repositori local]
    C -->|git push| D[Repositori remot]
    D -->|git pull| A
    B -->|git restore --staged| A
Zona Què conté Com s'hi entra Com se'n surt
Directori de treball Els fitxers del disc Editant git restore fitxer
Zona de preparació El que anirà al commit següent git add git restore --staged
Repositori La història ja confirmada git commit git revert

Gràcies a la zona intermèdia pots haver tocat cinc fitxers i confirmar-ne només dos, deixant la resta per a un altre commit amb la seva pròpia explicació. Aquesta disciplina —un commit, una idea— és el que converteix l'historial en una cosa útil de llegir.

  1. Les comandes del dia a dia

Amb aquestes deu comandes es cobreix el 95 % de la feina:

Comanda Què fa
git init Crea el repositori a la carpeta actual (apareix .git)
git status La més utilitzada: què has canviat i en quina zona és
git add fitxer Passa un canvi a la zona de preparació (git add . per a tot)
git commit -m "missatge" Confirma el que està preparat com una instantània
git log --oneline Historial compacte, un commit per línia
git diff Què has canviat i encara no has preparat
git diff --staged Què hi ha preparat per al commit següent
git show <hash> Tot el detall d'un commit concret
git restore fitxer Descarta els canvis no desats d'aquest fitxer
git rm fitxer Esborra el fitxer i registra l'esborrat

Així es veu una sessió real a TascaFàcil:

$ git status
On branch main
Changes not staged for commit:
        modified:   tascafacil/magatzem.py
        modified:   README.md

$ git add tascafacil/magatzem.py         # nomes aquest: el README anira en un altre commit
$ git commit -m "Sobreviure a un tasques.json corrupte o absent"
[main 4f2a9c1] Sobreviure a un tasques.json corrupte o absent
 1 file changed, 12 insertions(+), 3 deletions(-)

$ git log --oneline
4f2a9c1 Sobreviure a un tasques.json corrupte o absent
9b1e73d Documentar el paquet i afegir README
a07c5e2 Versio inicial de TascaFacil

Fixa't en el detall important: s'ha preparat un sol fitxer encara que n'hi havia dos de modificats. El commit resultant explica una història neta, i el README.md esperarà el seu propi commit. git status és la teva brúixola: executa'l abans i després de cada operació fins que el model mental et surti sol. I abans de confirmar, git diff t'ensenya exactament què desaràs:

$ git diff
diff --git a/tascafacil/magatzem.py b/tascafacil/magatzem.py
@@ -38,7 +38,10 @@ def carregar_tasques(ruta=RUTA_JSON):
-    with open(ruta, encoding="utf-8") as f:
-        return Agenda.from_dict(json.load(f))
+    try:
+        with open(ruta, encoding="utf-8") as f:
+            return Agenda.from_dict(json.load(f))
+    except FileNotFoundError:
+        return Agenda()

Les línies amb - són les que desapareixen i les que porten +, les que hi entren; la capçalera @@ -38,7 +38,10 @@ indica en quina part del fitxer som. Llegir un diff és la manera més ràpida de revisar la teva pròpia feina abans de confirmar-la.

  1. Què és un commit i com s'escriu el seu missatge

Un commit és quatre coses alhora: una instantània del projecte complet, un missatge que explica el perquè, un autor amb la seva data i un pare, el commit anterior. Aquesta cadena de pares és la història, i cada commit s'identifica amb un hash, un codi com 4f2a9c1 que serveix per referir-s'hi en qualsevol comanda.

El missatge és la part que més es descuida i la que més valor aporta d'aquí a sis mesos. Les regles acceptades a tots els projectes són tres: assumpte curt (menys de 50 caràcters), en imperatiu i sense punt final —«Afegeix», «Corregeix», «Elimina», com si completessis la frase «aquest commit...»—, i si cal, una línia en blanc i un cos que expliqui el perquè, mai el què (el què ja ho diu el diff).

Missatge dolent Per què Missatge bo
canvis No diu res Afegeix validacio de prioritat a Tasca
arreglat Què estava trencat? Corregeix el progres que superava el 100%
asdf Soroll pur Extreu demanar_prioritat a interficie.py
He canviat interficie.py i magatzem.py i de pas... Massa coses juntes Dos commits, un per idea
git commit -m "Apartar el JSON corrupte en lloc de perdre l" -m "Un fitxer malmes aturava l arrencada. Ara es reanomena a .json.bak i es
continua amb una agenda buida, perque la Marta pugui revisar-lo despres."

El segon -m crea el cos. Aquest text és exactament el que agrairàs quan d'aquí a un any et preguntis per què hi ha un fitxer .json.bak a la carpeta.

  1. .gitignore: el que mai no es versiona

No tot el que hi ha a la carpeta ha d'entrar al repositori. Un fitxer anomenat .gitignore, a l'arrel del projecte, diu què ha d'ignorar Git:

# Entorn virtual i cache de Python
.venv/
__pycache__/
*.pyc

# Dades locals i registres: cadascu te els seus
tasques.json
tasques.json.bak
tasques.csv
tascafacil.log

# Configuracio de l editor i del sistema
.vscode/
.DS_Store

# MAI credencials
.env
*.key

Les quatre categories són sempre les mateixes: el que es pot regenerar (__pycache__, el .venv, que es reconstrueix amb requirements.txt), les dades de cada usuari (el tasques.json de la Marta no és el d'en Luis), la configuració personal de l'editor i, sobretot, els secrets.

Aquest últim punt mereix un avís seriós: no pugis mai contrasenyes, claus d'API ni dades personals a un repositori. I no n'hi ha prou d'esborrar-les després en un commit posterior, perquè continuen sent a l'historial i qualsevol les pot recuperar; si el repositori és públic, hi ha robots que rastregen claus filtrades en qüestió de minuts. La regla és simple: les credencials van en un fitxer .env ignorat des del principi, i si alguna s'escapa, es revoca immediatament. El mateix val per a les dades personals de clients reals.

  1. Branques: treballar sense por

Una branca és una línia de desenvolupament paral·lela. Serveix per treballar en alguna cosa —una funcionalitat nova, un experiment, una correcció— sense tocar la versió que funciona, i perquè dues persones avancin alhora sense destorbar-se. A Git són tan barates que es fan servir constantment.

git branch                          # veure les branques (l actual porta *)
git switch -c exportar-pdf          # crear una branca i canviar-hi
... treballes i fas commits ...
git switch main                     # tornar a la principal
git merge exportar-pdf              # portar aqui la feina de la branca
git branch -d exportar-pdf          # esborrar-la quan ja esta fusionada

git switch és la forma moderna; veuràs molt git checkout en documentació antiga, que fa el mateix (i més coses, cosa que el feia confús).

gitGraph
    commit id: "Versio inicial"
    commit id: "Documentar paquet"
    branch exportar-pdf
    commit id: "Afegir exportacio PDF"
    commit id: "Ajustar marges"
    checkout main
    commit id: "Corregir progres"
    merge exportar-pdf
    commit id: "Versio 0.20"

Al diagrama, main va continuar avançant mentre la branca exportar-pdf feia la seva feina, i el merge va unir les dues històries en un commit de fusió. Mentre la branca existia, main va estar sempre en un estat funcional: això és el que significa «treballar sense por».

  1. Conflictes: què són i com es resolen

Un conflicte apareix quan dues branques han canviat les mateixes línies del mateix fitxer i Git no pot decidir quina val. No és un error ni una catàstrofe: és Git demanant-te que decideixis tu. En fusionar veuràs una cosa així:

Auto-merging tascafacil/interficie.py
CONFLICT (content): Merge conflict in tascafacil/interficie.py
Automatic merge failed; fix conflicts and then commit the result.

I dins del fitxer, les línies en disputa apareixen marcades:

<<<<<<< HEAD
AMPLE = 52                      # el que hi ha a la branca actual (main)
=======
AMPLE = 60                      # el que porta la branca que fusiones
>>>>>>> exportar-pdf

La resolució té tres passos, i cap no és misteriós: obre el fitxer i deixa-hi el contingut correcte, esborrant les tres línies de marques (<<<<<<<, =======, >>>>>>>); prepara el fitxer amb git add tascafacil/interficie.py; i tanca la fusió amb git commit. Si t'has embolicat, git merge --abort deixa tot com estava abans d'intentar-ho. El consell pràctic per tenir pocs conflictes: branques curtes, commits petits i fusionar sovint.

  1. Desfer: restore, revert i reset

Git permet desfer gairebé qualsevol cosa, però no totes les formes són igual de segures:

Ordre Què fa És segura en feina compartida?
git restore fitxer.py Descarta canvis no confirmats d'aquest fitxer
git restore --staged fitxer.py El treu de la zona de preparació
git revert <hash> Crea un commit nou que en desfà un d'anterior Sí: la recomanada
git reset --soft <hash> Mou la branca enrere, conservant els canvis Només en local
git reset --hard <hash> Mou la branca enrere i esborra els canvis Perillosa
$ git log --oneline
e5f80b2 Mostrar el resum de tasques per responsable
4f2a9c1 Sobreviure a un tasques.json corrupte o absent

$ git revert 4f2a9c1                # desfa aquest commit, sense esborrar-lo
$ git log --oneline
8d10c4a Revert "Sobreviure a un tasques.json corrupte o absent"
e5f80b2 Mostrar el resum de tasques per responsable
4f2a9c1 Sobreviure a un tasques.json corrupte o absent

Fixa't que el commit original continua sent-hi: revert no l'esborra, hi afegeix a sobre un altre que aplica exactament els canvis contraris. La diferència clau és aquesta: revert afegeix història, reset la reescriu. Si el commit ja està compartit amb altres persones, reescriure la història els trenca el repositori, així que la resposta correcta és gairebé sempre git revert. I git reset --hard mereix un respecte especial: esborra feina sense preguntar i no hi ha paperera. Fes-lo servir només al teu ordinador, sobre commits que ningú més no ha vist, i després de comprovar amb git status que no et deixes res.

  1. Remots: GitHub, GitLab i els pull requests

Un remot és una còpia del repositori allotjada en un altre lloc, normalment en un servei com GitHub o GitLab. Serveix de còpia de seguretat, de punt de trobada de l'equip i d'aparador: avui un repositori públic és part del currículum de qualsevol programador.

Comanda Què fa
git clone <url> Descarrega un repositori complet amb tot el seu historial
git remote add origin <url> Connecta el teu repositori local amb un de remot (origin és el nom habitual)
git push -u origin main Puja els teus commits al remot (la primera vegada, amb -u)
git fetch Porta els canvis del remot sense barrejar-los amb la teva feina
git pull fetch + merge: els porta i els integra a la teva branca

I una peça més que veuràs així que treballis amb altres: un pull request (o merge request a GitLab) és una petició formal de fusionar la teva branca a la principal. Obre una pàgina on l'equip veu els canvis línia a línia, comenta i aprova abans d'integrar. És el mecanisme amb què es revisa el codi a pràcticament tots els projectes, i funciona exactament sobre les branques que ja saps crear.

  1. Etiquetes i versionatge

Una etiqueta (tag) és un nom permanent per a un commit concret, i el seu ús natural és marcar les versions publicades —justament els números que véns veient des de 08-01:

git tag -a v0.20 -m "Projecte sota control de versions"
git tag                            # llistar les etiquetes
git show v0.20                     # veure a quin commit correspon
git push origin v0.20              # les etiquetes es pugen a part

A diferència d'una branca, una etiqueta no es mou: v0.20 assenyalarà aquell commit per sempre, així que d'aquí a un any podràs recuperar exactament el codi que es va lliurar. Aquí és on el versionatge semàntic de 08-01 es fa tangible: v0.19, v0.20, v1.0 deixen de ser una convenció mental per convertir-se en punts concrets i recuperables de l'historial.

  1. TascaFàcil v0.20: el projecte sota Git

Posarem el paquet sota control de versions des de zero, amb tres commits que expliquen una història i una branca per a una millora:

$ cd ~/projectes/tascafacil
$ git init
Initialized empty Git repository in /home/marta/projectes/tascafacil/.git/

$ printf '.venv/\n__pycache__/\n*.pyc\ntasques.json\ntascafacil.log\n' > .gitignore
$ git add .gitignore
$ git commit -m "Afegir .gitignore amb entorn, cache i dades locals"

$ git add tascafacil/ README.md
$ git status                        # comprovar que NO hi entra tasques.json
$ git commit -m "Afegir el paquet tascafacil documentat (v0.18)"

$ git add tascafacil/magatzem.py tascafacil/model.py tascafacil/interficie.py
$ git commit -m "Gestionar errors de carrega i de validacio (v0.19)"
$ git tag -a v0.19 -m "El programa deixa de trencar-se"

L'ordre no és casual: el .gitignore va primer, abans d'afegir res més, perquè el tasques.json amb les dades reals no entri mai a l'historial. Ara, la millora en una branca:

$ git switch -c resum-per-responsable
$ ... editar agenda.py i interficie.py ...
$ git add tascafacil/agenda.py tascafacil/interficie.py
$ git commit -m "Mostrar el resum de tasques per responsable al menu"
$ git switch main
$ git merge resum-per-responsable
Updating 7c3d1a9..e5f80b2
Fast-forward
 tascafacil/agenda.py  | 14 ++++++++++++++
 tascafacil/interficie.py |  8 ++++++++
$ git branch -d resum-per-responsable

$ git log --oneline --graph
* e5f80b2 (HEAD -> main) Mostrar el resum de tasques per responsable
* 7c3d1a9 (tag: v0.19) Gestionar errors de carrega i de validacio (v0.19)
* 9b1e73d Afegir el paquet tascafacil documentat (v0.18)
* a07c5e2 Afegir .gitignore amb entorn, cache i dades locals

Fast-forward significa que main no havia avançat mentre treballaves, així que Git simplement va avançar el punter: ni tan sols va caldre un commit de fusió. TascaFàcil v0.20 té ja historial, autoria, missatges que expliquen el perquè, una etiqueta i la capacitat de tornar a qualsevol punt anterior.

Errors Habituals i Consells

  • Pujar l'entorn virtual o les dades. Crea el .gitignore abans del primer git add .; treure alguna cosa de l'historial després és molt més incòmode.
  • Pujar contrasenyes o dades personals. Queden a l'historial encara que les esborris després. Fes servir un .env ignorat i revoca qualsevol clau que s'escapi.
  • Commits gegants. «Canvis de la setmana» amb 40 fitxers no serveix per a res. Un commit, una idea.
  • Missatges buits (canvis, fix, asdf). Escriu en imperatiu què fa el commit i, si no és obvi, per què.
  • Treballar sempre a main. Per a qualsevol cosa que no sigui trivial, obre una branca: si surt malament, l'esborres i no ha passat res.
  • Fer servir git reset --hard per «netejar». Esborra feina sense preguntar. En una cosa compartida, fes servir git revert.
  • Consell: git status i git diff abans de cada commit. Mirar el que estàs a punt de confirmar evita el 90 % dels ensurts i dels fitxers colats per error.

Exercicis

Exercici 1: Missatges de commit

Reescriu aquests quatre missatges seguint les regles vistes, i indica en quin d'ells partiries la feina en més d'un commit:

  1. arreglos diversos
  2. S'ha modificat el fitxer interficie.py perquè ara el menú mostri també l'opció d'exportar i de passada he corregit un error en el càlcul del progrés
  3. wip
  4. afegida funció

Exercici 2: .gitignore per a un projecte nou

La Marta engega informes, un programa que llegeix el tasques.json de TascaFàcil, desa plantilles a plantilles/, genera PDF a sortida/, fa servir un entorn virtual .venv i necessita una clau de l'API de correu. Escriu el seu .gitignore explicant cada línia i digues què que s'ha de versionar.

Exercici 3: Una branca amb conflicte

Descriu, comanda a comanda, aquesta situació completa: crees la branca menu-curt, canvies AMPLE = 52 per AMPLE = 48 a interficie.py i fas commit; mentrestant, a main, una altra persona va canviar aquesta mateixa línia a AMPLE = 60 i ho va confirmar. Fusiona, resol el conflicte deixant AMPLE = 48 i tanca l'operació.

Solucions

Solució 1.

Original Reescrit
arreglos diversos Corregeix l arrodoniment del progres a Tasca.progres
El llarg del punt 2 Dos commits: Afegeix l opcio d exportar al menu i Corregeix el calcul del progres
wip Extreu demanar_prioritat a interficie.py (i si de debò està a mitges, no es confirma a main: es queda a la seva branca)
afegida funció Afegeix resum_per_responsable a Agenda

El cas interessant és el segon: barreja dues idees independents, i això té una conseqüència pràctica molt concreta. Si demà cal desfer la correcció del progrés, amb un sol commit s'enduria per davant també l'opció del menú. Un commit per idea és el que fa que git revert sigui una operació quirúrgica i no una demolició.

Solució 2.

# Entorn virtual: es reconstrueix amb requirements.txt
.venv/

# Cache de Python: es regenera sola
__pycache__/
*.pyc

# Dades d entrada i resultats: cada usuari te els seus
tasques.json
sortida/

# Credencials: MAI al repositori
.env

Sí que s'ha de versionar tot el que és el projecte i no un producte seu: el codi font, el README.md, el requirements.txt, la carpeta plantilles/ —perquè les plantilles són part del programa, no un resultat— i un .env.example amb les claus buides, que documenta quines variables calen sense revelar-ne cap. La regla que ho resumeix tot: versiona el que escrius; ignora el que es genera, el que és personal i el que és secret.

Solució 3.

$ git switch -c menu-curt
$ ... canviar AMPLE a 48 a tascafacil/interficie.py ...
$ git add tascafacil/interficie.py
$ git commit -m "Reduir l ample del menu a 48 columnes"

$ git switch main                       # main ja te el canvi a 60
$ git merge menu-curt
Auto-merging tascafacil/interficie.py
CONFLICT (content): Merge conflict in tascafacil/interficie.py

$ ... obrir el fitxer, deixar nomes 'AMPLE = 48' i esborrar <<<<<<<, ======= i >>>>>>>
$ git add tascafacil/interficie.py      # 'add' es la manera de dir "resolt"
$ git commit -m "Fusionar menu-curt: es mante AMPLE a 48"
$ git branch -d menu-curt

Tres detalls que convé fixar. El conflicte no ha trencat res: fins que no confirmis, el repositori està en un estat intermedi del qual se surt amb git commit o del qual es fuig amb git merge --abort. git add és el senyal de «ja està resolt», no una operació diferent. I cal revisar el fitxer sencer abans de confirmar, perquè és fàcil deixar-se una marca >>>>>>> oblidada que convertiria el mòdul en codi amb error de sintaxi.

Conclusió

Un sistema de control de versions substitueix les carpetes _v3_bo_definitiu per un historial real: instantànies amb data, autor i explicació, amb la possibilitat de comparar, tornar enrere i combinar la feina de diverses persones. Git és distribuït, així que cada clon conté la història completa. Es configura una vegada amb git config --global user.name i user.email, que signen tots els teus commits. El seu model mental són tres zones —directori de treball, zona de preparació i repositori—, i el recorregut d'un canvi és sempre addcommit → (push). El dia a dia cap en deu comandes: init, status, add, commit -m, log --oneline, diff, show, restore i rm, amb git status com a brúixola permanent. Un commit és instantània, missatge, autor i pare, i el seu missatge s'escriu en imperatiu, curt i explicant el perquè, amb un commit per idea. El .gitignore deixa fora l'entorn virtual, __pycache__, les dades locals, la configuració de l'editor i —això sense excepcions— les credencials, que romanen a l'historial encara que les esborris després. Les branques (branch, switch -c, merge, -d) permeten treballar sense tocar la versió bona, i un conflicte no és una catàstrofe: s'edita el fitxer deixant-hi el contingut correcte, s'esborren les marques <<<<<<<, ======= i >>>>>>>, es fa git add i es confirma. Per desfer, restore amb el que no està confirmat i revert amb el que ja ho està —afegeix història en lloc de reescriure-la—, deixant reset --hard per al que és estrictament local. Els remots (clone, remote add, push, pull, fetch) porten el projecte a GitHub o GitLab, on un pull request permet revisar el codi abans d'integrar-lo. I les etiquetes (git tag -a v1.0) fixen per sempre els números del versionatge semàntic.

TascaFàcil és ara la v0.20: un repositori amb el seu .gitignore, tres commits que expliquen què es va fer i per què, una etiqueta v0.19 i una branca fusionada i esborrada. Pots experimentar sense por, perquè no es perd res. I tanmateix, hi ha una cosa que Git no et pot dir: si el codi que acabes de confirmar funciona. Cada vegada que toques Agenda.ordenades() o la validació de Tasca, continues engegant el menú i provant opcions a mà, una per una, pregant per no haver trencat res del que ja funcionava. Això és lent, és avorrit i es fa malament. A Proves automatitzades construiràs la xarxa de seguretat que faltava: una carpeta tests/ amb proves que comproven soles, en un segon, que tot continua al seu lloc.

© Copyright 2026. Tots els drets reservats