Fins ara sempre hem mirat endavant: crear el repositori, preparar canvis, confirmar-los, revisar el diff abans de registrar-lo. Aquesta lliçó canvia el sentit de la mirada. Anem a consultar el passat.
I aquí hi ha el veritable valor de Git. Desar versions no serveix de gaire si després no pots respondre preguntes com ara: quan es va introduir aquesta funció? Qui va tocar estils.css la setmana passada i per què? En quina confirmació va desaparèixer aquella línia que juraries haver escrit? Què es va fer al projecte entre dilluns i dijous?
git log les respon totes, però la seva sortida per defecte és només la punta de l'iceberg. És una ordre enormement configurable: formats compactes, gràfics, resums per fitxer, plantilles pròpies i una bateria de filtres que permeten localitzar una confirmació entre milers. En aquesta lliçó la recorrerem sencera, juntament amb git show per inspeccionar una confirmació concreta i les diferents formes de referir-se a un commit, que hem anat fent servir de passada (HEAD, HEAD~1) sense explicar-les del tot.
Contingut
- El repositori d'en Bruno: el nostre banc de proves
git logper defecte- Formats compactes:
--onelinei--graph - Veure què va canviar:
--stati--patch - Formats personalitzats amb
--pretty=format: - Filtrar l'historial: quantitat, dates, autor i missatge
- Filtrar per ruta i la cerca «pickaxe» (
-Si-G) git show: inspeccionar una confirmació- Com referir-se a una confirmació
- Combinacions útils per al dia a dia
- El repositori d'en Bruno: el nostre banc de proves
Han passat uns dies des que en Bruno va clonar el projecte. L'Ana ja tenia quatre confirmacions quan ell hi va arribar, i des de llavors en Bruno n'ha fet tres més a la seva pròpia còpia. Aquest és l'historial que té al seu MacBook:
b2e6d3f (HEAD -> main) Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 Aplica estil a les tasques completades 3d5b8e1 Afegeix el filtre de tasques pendents c5d9b1e (origin/main, origin/HEAD) Documenta la instal·lació al README 4e7f2a9 Afegeix l'esborrat de tasques al llistat 8b6d3c2 Afegeix els estils base del llistat 1a4c8d6 Estructura inicial del gestor de tasques
Set confirmacions: les quatre de l'Ana que van arribar amb el clon i les tres que ha fet en Bruno en local. Fixa't en (origin/main): marca el punt on era el servidor quan en Bruno va clonar. Les seves tres confirmacions són per davant d'aquella marca perquè encara no les ha enviat; això és matèria del mòdul 4.
Aquest historial mixt ens anirà molt bé: té dos autors, dates diferents i canvis sobre fitxers diferents, que és justament el que necessitem per practicar els filtres.
git log per defecte
git log per defectecommit b2e6d3f8a1c5e9d2b4f7a3c6e8d1b5f9a2c4e7d3 (HEAD -> main) Author: Bruno Salas <[email protected]> Date: Fri Jul 31 09:14:22 2026 +0200 Corregeix el focus del camp després d'afegir una tasca En enviar el formulari el cursor es perdia i calia tornar a clicar al camp. Ara es retorna el focus. commit 7c1f4a9e2b6d8f3a5c1e7b9d4f2a6c8e3b5d1f7a Author: Bruno Salas <[email protected]> Date: Thu Jul 30 17:42:08 2026 +0200 Aplica estil a les tasques completades commit 3d5b8e1c4a7f2d9b6e3c8a1f5d2b7e4c9a6f3d8b Author: Bruno Salas <[email protected]> Date: Wed Jul 29 11:05:47 2026 +0200 Afegeix el filtre de tasques pendents
(La sortida continua; se surt del paginador amb q.)
Cada entrada té quatre elements:
| Element | Què és |
|---|---|
commit <hash> |
El SHA complet de 40 caràcters del commit |
Author |
Qui va escriure el canvi, amb el user.name i user.email que va configurar |
Date |
Data d'autoria, amb zona horària |
| Missatge | Indentat quatre espais; primera línia i cos |
Un parell de precisions importants:
- L'ordre és cronològic invers: el més recent a dalt. És el que vols el 95 % de les vegades. S'inverteix amb
--reverse. AuthoriCommittersón camps diferents. Recorda del model de dades que un commit desa tots dos. Normalment coincideixen igit lognomés mostra el primer; se separen quan algú aplica un pedaç aliè o en fer rebase. Per veure'ls tots dos:
commit b2e6d3f8a1c5e9d2b4f7a3c6e8d1b5f9a2c4e7d3 (HEAD -> main) Author: Bruno Salas <[email protected]> AuthorDate: Fri Jul 31 09:14:22 2026 +0200 Commit: Bruno Salas <[email protected]> CommitDate: Fri Jul 31 09:14:22 2026 +0200
git lognomés mostra l'historial assolible des d'on ets. Per defecte parteix deHEADi va seguint els enllaços als pares. Confirmacions que existeixin en altres branques no hi apareixen llevat que les demanis explícitament o facis servir--all.
- Formats compactes:
--oneline i --graph
--oneline i --graph--oneline
b2e6d3f (HEAD -> main) Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 Aplica estil a les tasques completades 3d5b8e1 Afegeix el filtre de tasques pendents c5d9b1e (origin/main, origin/HEAD) Documenta la instal·lació al README 4e7f2a9 Afegeix l'esborrat de tasques al llistat 8b6d3c2 Afegeix els estils base del llistat 1a4c8d6 Estructura inicial del gestor de tasques
Una línia per confirmació: hash abreujat, referències que hi apunten i primera línia del missatge. És el format que més es fa servir, i explica per què aquella primera línia ha de funcionar tota sola: en aquesta vista és l'únic que es veu.
--oneline és en realitat una drecera de --pretty=oneline --abbrev-commit.
--graph
Dibuixa el graf de confirmacions amb caràcters de text:
* b2e6d3f (HEAD -> main) Corregeix el focus del camp després d'afegir una tasca * 7c1f4a9 Aplica estil a les tasques completades * 3d5b8e1 Afegeix el filtre de tasques pendents * c5d9b1e (origin/main, origin/HEAD) Documenta la instal·lació al README * 4e7f2a9 Afegeix l'esborrat de tasques al llistat * 8b6d3c2 Afegeix els estils base del llistat * 1a4c8d6 Estructura inicial del gestor de tasques
Amb una sola línia de desenvolupament, el gràfic és una columna d'asteriscs i no aporta gaire. El seu valor apareix quan hi ha branques i fusions, on mostra les bifurcacions i els punts d'unió:
* 9f3a2c1 (HEAD -> main) Fusiona la branca filtres |\ | * 5e8b1d4 Afegeix el filtre per data | * 2c7f9a3 Afegeix el selector de filtres * | 8d4e6b2 Corregeix el comptador |/ * c5d9b1e Documenta la instal·lació al README
Aquest és l'aspecte que tindrà l'historial de l'equip a partir del mòdul 3. Per veure el graf de totes les branques, no només l'actual:
--decorate mostra les referències (branques, etiquetes, HEAD) al costat de cada confirmació. A Git modern està activat per defecte al terminal, però convé conèixer-lo.
- Veure què va canviar:
--stat i --patch
--stat i --patch--stat: resum per fitxers
commit b2e6d3f8a1c5e9d2b4f7a3c6e8d1b5f9a2c4e7d3 (HEAD -> main) Author: Bruno Salas <[email protected]> Date: Fri Jul 31 09:14:22 2026 +0200 Corregeix el focus del camp després d'afegir una tasca app.js | 2 ++ 1 file changed, 2 insertions(+) commit 7c1f4a9e2b6d8f3a5c1e7b9d4f2a6c8e3b5d1f7a Author: Bruno Salas <[email protected]> Date: Thu Jul 30 17:42:08 2026 +0200 Aplica estil a les tasques completades estils.css | 7 +++++++ 1 file changed, 7 insertions(+) commit 3d5b8e1c4a7f2d9b6e3c8a1f5d2b7e4c9a6f3d8b Author: Bruno Salas <[email protected]> Date: Wed Jul 29 11:05:47 2026 +0200 Afegeix el filtre de tasques pendents app.js | 18 ++++++++++++++++-- index.html | 6 ++++++ 2 files changed, 22 insertions(+), 2 deletions(-)
És la vista més útil per fer-se una idea ràpida de la mida i l'abast de cada canvi sense llegir el codi. Variants:
git log --shortstat -3 # només la línia de totals
git log --name-only -3 # només els noms de fitxer
git log --name-status -3 # noms amb M/A/D/R--patch (o -p): el diff complet
commit b2e6d3f8a1c5e9d2b4f7a3c6e8d1b5f9a2c4e7d3 (HEAD -> main) Author: Bruno Salas <[email protected]> Date: Fri Jul 31 09:14:22 2026 +0200 Corregeix el focus del camp després d'afegir una tasca En enviar el formulari el cursor es perdia i calia tornar a clicar al camp. Ara es retorna el focus. diff --git a/app.js b/app.js index 3c9d4a2..5f8b2e1 100644 --- a/app.js +++ b/app.js @@ -58,5 +58,6 @@ document.querySelector('#nova-tasca').addEventListener('submit', function (esdev if (camp.value.trim() !== '') { afegeixTasca(camp.value.trim()); camp.value = ''; + camp.focus(); } });
Mostra l'historial amb el diff de cada confirmació, en el format unified diff que vas aprendre a llegir a la lliçó anterior. És la manera més completa de revisar feina, i també la més llarga: fes-la servir sempre amb un límit (-1, -5) o combinada amb un filtre.
Una combinació especialment valuosa:
Mostra l'evolució completa d'un sol fitxer, confirmació a confirmació, amb el diff de cadascuna. És com veure una pel·lícula del fitxer des del seu naixement.
- Formats personalitzats amb
--pretty=format:
--pretty=format:Quan cap dels formats predefinits no encaixa, pots dissenyar el teu amb una plantilla:
b2e6d3f · Bruno Salas · fa 5 hores · Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 · Bruno Salas · fa 20 hores · Aplica estil a les tasques completades 3d5b8e1 · Bruno Salas · fa 2 dies · Afegeix el filtre de tasques pendents c5d9b1e · Ana Ferrer · fa 5 dies · Documenta la instal·lació al README 4e7f2a9 · Ana Ferrer · fa 7 dies · Afegeix l'esborrat de tasques al llistat 8b6d3c2 · Ana Ferrer · fa 9 dies · Afegeix els estils base del llistat 1a4c8d6 · Ana Ferrer · fa 11 dies · Estructura inicial del gestor de tasques
Els marcadors comencen per %. Aquests són els que de debò es fan servir:
| Marcador | Contingut | Exemple |
|---|---|---|
%H |
Hash complet | b2e6d3f8a1c5e9d2b4f7a3c6e8d1b5f9a2c4e7d3 |
%h |
Hash abreujat | b2e6d3f |
%T / %t |
Hash de l'arbre (complet / abreujat) | 9f4c2a8 |
%P / %p |
Hash dels pares | 7c1f4a9 |
%an |
Nom de l'autor | Bruno Salas |
%ae |
Correu de l'autor | [email protected] |
%ad |
Data d'autoria | Fri Jul 31 09:14:22 2026 +0200 |
%ar |
Data d'autoria relativa | fa 5 hores |
%as |
Data d'autoria curta | 2026-07-31 |
%cn / %ce / %cd / %cr |
El mateix per al committer | |
%s |
Assumpte (primera línia del missatge) | Corregeix el focus… |
%b |
Cos del missatge | |
%d |
Referències (branques, etiquetes) | (HEAD -> main) |
%D |
Referències sense parèntesis | HEAD -> main |
%n |
Salt de línia | |
%% |
Un signe de percentatge literal |
Afegir color
Els marcadors %C... controlen el color i fan la sortida molt més llegible:
git log --pretty=format:"%C(yellow)%h%C(reset) %C(blue)%ad%C(reset) %C(green)%an%C(reset) %s" --date=shortb2e6d3f 2026-07-31 Bruno Salas Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 2026-07-30 Bruno Salas Aplica estil a les tasques completades 3d5b8e1 2026-07-29 Bruno Salas Afegeix el filtre de tasques pendents c5d9b1e 2026-07-26 Ana Ferrer Documenta la instal·lació al README
Colors disponibles: red, green, yellow, blue, magenta, cyan, white, i %C(auto) perquè Git decideixi. %C(reset) torna al color normal, i %C(bold …) dona negreta.
Controlar el format de la data
git log --date=short --pretty=format:"%ad %s" # 2026-07-31
git log --date=relative --pretty=format:"%ad %s" # fa 5 hores
git log --date=iso --pretty=format:"%ad %s" # 2026-07-31 09:14:22 +0200
git log --date=format:"%d/%m/%Y" --pretty=format:"%ad %s" # 31/07/2026Un àlies que val la pena
Aquesta plantilla és un clàssic i mereix desar-se com a àlies:
git config --global alias.lg "log --graph --pretty=format:'%C(yellow)%h%C(reset)%C(auto)%d%C(reset) %s %C(dim)(%ar) <%an>%C(reset)' --abbrev-commit"* b2e6d3f (HEAD -> main) Corregeix el focus del camp després d'afegir una tasca (fa 5 hores) <Bruno Salas> * 7c1f4a9 Aplica estil a les tasques completades (fa 20 hores) <Bruno Salas> * 3d5b8e1 Afegeix el filtre de tasques pendents (fa 2 dies) <Bruno Salas> * c5d9b1e (origin/main, origin/HEAD) Documenta la instal·lació al README (fa 5 dies) <Ana Ferrer> * 4e7f2a9 Afegeix l'esborrat de tasques al llistat (fa 7 dies) <Ana Ferrer>
Els àlies es desen al ~/.gitconfig amb el mecanisme que vam veure a Configurant Git, i es tracten a fons a Git Log i Àlies.
- Filtrar l'historial: quantitat, dates, autor i missatge
En un projecte de dos anys, git log retorna milers d'entrades. Els filtres són el que converteix l'ordre en una eina de cerca.
Per quantitat
git log -3 # les 3 últimes
git log -n 3 # equivalent
git log --skip=3 -3 # les 3 anteriors a aquestesPer data
git log --since="2026-07-29"
git log --after="2026-07-29" # sinònim de --since
git log --until="2026-07-30"
git log --before="2026-07-30" # sinònim de --until
# Combinades: una finestra temporal
git log --since="2026-07-25" --until="2026-07-30" --onelineGit accepta expressions en llenguatge natural (en anglès), cosa que és molt còmoda:
git log --since="2 weeks ago"
git log --since="yesterday"
git log --since="last monday"
git log --since="3 days ago" --until="1 day ago"Per autor
c5d9b1e Documenta la instal·lació al README 4e7f2a9 Afegeix l'esborrat de tasques al llistat 8b6d3c2 Afegeix els estils base del llistat 1a4c8d6 Estructura inicial del gestor de tasques
El valor és una expressió regular que es busca tant al nom com al correu, així que n'hi ha prou amb un fragment:
I el filtre simètric per al confirmador:
Per missatge
També és una expressió regular, i per defecte distingeix majúscules. Per ignorar-les:
Diversos --grep es combinen amb O lògic per defecte; --all-match els converteix en I:
git log --grep="tasca" --grep="estil" --oneline # qualsevol dels dos
git log --grep="tasca" --grep="estil" --all-match --oneline # tots dos alhoraI compte amb això: quan combines filtres de tipus diferent, s'apliquen amb I lògic:
Confirmacions d'en Bruno, del 30 de juliol endavant, el missatge de les quals contingui «estil». Una de sola.
- Filtrar per ruta i la cerca «pickaxe» (
-S i -G)
-S i -G)Per ruta
Només les confirmacions que van modificar aquell fitxer. Igual que a git diff, el -- separa opcions de rutes i és obligatori quan el nom es podria confondre amb una branca.
Accepta directoris i patrons:
Combinat amb -p, és la millor manera d'entendre com va arribar un fitxer a ser el que és:
--follow segueix el fitxer a través de reanomenaments. Sense aquesta opció, l'historial es tallaria en el moment en què el fitxer va canviar de nom. Només funciona amb un fitxer alhora.
La cerca «pickaxe»: -S
Aquí arriba una de les capacitats més útils i menys conegudes de Git. -S busca les confirmacions en què va canviar el nombre d'aparicions d'una cadena. A la pràctica: quan es va introduir o es va eliminar aquell text.
Una sola confirmació: aquella en què va aparèixer la funció. Si més endavant algú l'esborrés, aquella confirmació també hi sortiria.
Compara-ho amb --grep, que és una cosa completament diferent:
| Opció | Busca a | Respon a |
|---|---|---|
--grep="X" |
El missatge del commit | Qui va escriure «X» en un missatge? |
-S "X" |
El contingut dels fitxers | Quan va aparèixer o desaparèixer «X» al codi? |
-G "X" |
El contingut, per expressió regular | Quins commits van tocar línies que casen amb «X»? |
El cas d'ús estrella de -S és aquest: trobes al codi una línia estranya, vols saber per què hi és, i git blame només et diu qui la va tocar per última vegada. Amb -S trobes la confirmació original que la va introduir, amb el seu missatge explicatiu.
Mostra la confirmació on va aparèixer aquella declaració CSS, amb el seu diff. Cerca quirúrgica.
Per veure-ho amb més detall:
-G: la variant per expressió regular
La diferència amb -S és subtil però important:
-S "text"troba els commits on va canviar el nombre de vegades que apareix aquell text. Si mous una línia de lloc dins del mateix fitxer, el nombre no canvia i-Sno la troba.-G "regex"troba tots els commits el diff dels quals conté alguna línia afegida o eliminada que casi amb l'expressió. Un moviment sí que hi apareix.
Regla pràctica: -S per a «quan es va introduir això?»; -G per a «quins commits van tocar alguna cosa semblant a això?».
Totes dues accepten --pickaxe-regex i es combinen amb la resta de filtres:
git show: inspeccionar una confirmació
git show: inspeccionar una confirmacióQuan ja has localitzat la confirmació que t'interessa, git show te l'ensenya sencera:
commit 3d5b8e1c4a7f2d9b6e3c8a1f5d2b7e4c9a6f3d8b Author: Bruno Salas <[email protected]> Date: Wed Jul 29 11:05:47 2026 +0200 Afegeix el filtre de tasques pendents diff --git a/app.js b/app.js index 5f8b2e1..8c3a7d9 100644 --- a/app.js +++ b/app.js @@ -30,6 +30,9 @@ function pintaLlista() { const llista = document.querySelector('#llista'); llista.innerHTML = ''; - for (const tasca of tasques) { + const visibles = nomesPendents + ? tasques.filter(function (t) { return !t.feta; }) + : tasques; + for (const tasca of visibles) { ...
Metadades i diff en una sola vista. És equivalent a git log -p -1 <commit>, però més directe.
git show és més versàtil del que sembla, perquè accepta qualsevol objecte de Git:
# Una confirmació
git show 3d5b8e1
# La confirmació actual
git show
git show HEAD
# Només el resum per fitxers
git show --stat 3d5b8e1
# Només el missatge, sense diff
git show --no-patch 3d5b8e1
git show -s 3d5b8e1 # abreujat
# Només el nom dels fitxers afectats
git show --name-only 3d5b8e1
# Un fitxer TAL COM ERA en aquella confirmació
git show 3d5b8e1:app.js
# El mateix fitxer fa tres confirmacions
git show HEAD~3:estils.css
# Un arbre (el contingut d'un directori en aquell moment)
git show 3d5b8e1^{tree}La sintaxi <commit>:<ruta> és especialment útil. Ja la vam fer servir al mòdul anterior per comprovar quina versió d'un fitxer havia quedat registrada. Serveix, per exemple, per recuperar una versió antiga sense tocar res més:
I combinada amb -s i un format, git show serveix per extreure dades concretes:
git show -s --format="%an va escriure això el %as" HEAD
# → Bruno Salas va escriure això el 2026-07-31
- Com referir-se a una confirmació
Portem estona fent servir HEAD, HEAD~1 i hashos sense haver sistematitzat la notació. Tanquem-la, perquè apareix pràcticament a totes les ordres de Git.
El hash
git show b2e6d3f8a1c5e9d2b4f7a3c6e8d1b5f9a2c4e7d3 # complet
git show b2e6d3f # abreujat
git show b2e6 # encara més curtN'hi ha prou d'escriure un prefix inequívoc. Git necessita almenys 4 caràcters i en fa servir 7 per defecte en mostrar-los. En repositoris molt grans pot caldre'n algun més; si el prefix és ambigu, Git t'avisa:
Les referències simbòliques
| Referència | Significa |
|---|---|
HEAD |
La confirmació on ets ara |
main |
La confirmació a la qual apunta la branca main |
origin/main |
L'última confirmació coneguda de main al remot |
v1.0 |
La confirmació etiquetada com a v1.0 |
@ |
Sinònim abreujat de HEAD |
Els operadors ~ i ^
Aquests dos són els que confonen, i la diferència només importa quan hi ha fusions (commits amb més d'un pare):
| Notació | Significa |
|---|---|
HEAD~1 o HEAD~ |
El primer pare de HEAD (la confirmació anterior) |
HEAD~2 |
El primer pare del primer pare: dues confirmacions enrere |
HEAD~n |
n confirmacions enrere, seguint sempre el primer pare |
HEAD^1 o HEAD^ |
El primer pare de HEAD — idèntic a HEAD~1 |
HEAD^2 |
El segon pare de HEAD (només existeix en una fusió) |
HEAD^^ |
El pare del pare — idèntic a HEAD~2 |
En resum:
~recorre generacions cap enrere per la línia principal.~3= tres passos enrere.^tria entre els pares d'un mateix commit.^2= el segon pare.
En un historial lineal com el d'en Bruno, HEAD~2 i HEAD^^ són exactament el mateix:
git rev-parse HEAD~2
# → 3d5b8e1c4a7f2d9b6e3c8a1f5d2b7e4c9a6f3d8b
git rev-parse HEAD^^
# → 3d5b8e1c4a7f2d9b6e3c8a1f5d2b7e4c9a6f3d8bEl diagrama ho aclareix:
graph RL
C7["b2e6d3f<br/>HEAD"] --> C6["7c1f4a9<br/>HEAD~1<br/>HEAD^"]
C6 --> C5["3d5b8e1<br/>HEAD~2<br/>HEAD^^"]
C5 --> C4["c5d9b1e<br/>HEAD~3"]
C4 --> C3["4e7f2a9<br/>HEAD~4"]
C3 --> C2["8b6d3c2<br/>HEAD~5"]
C2 --> C1["1a4c8d6<br/>HEAD~6<br/>(root-commit)"]
Les fletxes apunten cap enrere perquè així és com funciona Git: cada commit coneix el seu pare, no els seus fills. Per això és fàcil recórrer l'historial cap al passat i no existeix una notació senzilla per anar cap al futur.
I quan hi hagi fusions (mòdul 3), ^ prendrà sentit:
graph RL
M["9f3a2c1<br/>fusió"] -->|"^1 (o ~1)"| A["8d4e6b2<br/>main"]
M -->|"^2"| B["5e8b1d4<br/>branca filtres"]
Rangs
Dos punts defineixen un rang de confirmacions:
Es llegeix com «les confirmacions assolibles des de c5d9b1e però no des de 8b6d3c2». És a dir: el que hi ha després de 8b6d3c2 fins a c5d9b1e inclòs. Fixa't que l'extrem esquerre queda fora.
Formes molt utilitzades:
git log HEAD~3..HEAD --oneline # les 3 últimes confirmacions
git log origin/main..HEAD --oneline # el que tinc i el remot no
git log HEAD..origin/main --oneline # el que té el remot i jo noAquest penúltim és exactament el que en Bruno té pendent d'enviar:
b2e6d3f Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 Aplica estil a les tasques completades 3d5b8e1 Afegeix el filtre de tasques pendents
Les seves tres confirmacions locals. Tot això es desenvoluparà al mòdul 4.
Resoldre qualsevol referència
git rev-parse tradueix qualsevol notació a un hash complet, i és la manera de sortir de dubtes:
git rev-parse HEAD~3 # → c5d9b1e...
git rev-parse main # → b2e6d3f...
git rev-parse --short HEAD # → b2e6d3f
- Combinacions útils per al dia a dia
Un receptari de consultes que resolen preguntes reals:
# Què s'ha fet aquesta setmana?
git log --since="1 week ago" --oneline
# Què he fet jo aquesta setmana? (per a l'informe del divendres)
git log --author="$(git config user.name)" --since="1 week ago" --oneline
# Quantes confirmacions té el projecte?
git rev-list --count HEAD
# Qui hi ha contribuït i quant?
git shortlog -sn# Com va evolucionar aquest fitxer?
git log -p --follow -- estils.css
# Quan es va introduir aquesta cadena?
git log -S "actualitzaComptador" --oneline
# Quins fitxers toca més el projecte?
git log --name-only --pretty=format: | sort | uniq -c | sort -rn | head
# L'última confirmació que va tocar cada fitxer
git log --name-status -5
# Historial en una línia amb data i autor
git log --pretty=format:"%h %as %an %s"
# Quines confirmacions NO són al remot?
git log origin/main..HEAD --onelineI una advertència pràctica: git log obre un paginador. Es recorre amb les fletxes o la barra espaiadora, s'hi busca amb /text i se'n surt amb q. Si prefereixes la sortida directa:
Errors Habituals i Consells
- Confondre
--grepamb-S.--grepbusca al missatge de la confirmació;-Sbusca al contingut dels fitxers. Són preguntes completament diferents i és l'error més freqüent en buscar a l'historial. - Oblidar el
--abans d'una ruta.git log estils.cssfunciona si no hi ha ambigüitat, perògit log maininterpretaràmaincom una branca. Posa-hi--sempre que puguis dubtar. - Esperar que
git logmostri totes les branques. Per defecte només recorre l'historial assolible des deHEAD. Per veure-ho tot,--all. - Interpretar malament els rangs
a..b. L'extrem esquerre no s'hi inclou.git log HEAD~3..HEADretorna tres confirmacions, no quatre. - Fer servir
~quan es vol^. En un historial lineal són intercanviables, però en una fusióHEAD^2(el segon pare) iHEAD~2(dues generacions enrere) apunten a llocs diferents. - Quedar-se atrapat al paginador. Se'n surt amb
q. És una de les primeres frustracions de tothom amb Git. - Buscar dins de
git log -pa ull. Si busques on va aparèixer un text concret,-St'ho dona en una ordre en lloc de fer-te llegir cent diffs. - No fer servir
--followen mirar l'historial d'un fitxer reanomenat. Veuràs un historial que «comença» al reanomenament i conclouràs erròniament que el fitxer és recent. - Consell: defineix l'àlies
lgde l'apartat 5. El faràs servir a diari i fa l'historial molt més llegible. - Consell:
git shortlog -snés la manera més ràpida de saber qui treballa en un projecte que acabes de clonar. Igit log --oneline -20et dona el pols del que s'està fent ara mateix. - Consell: si vols exportar l'historial per a un informe,
--pretty=format:combinat amb--date=shortprodueix línies fàcils de processar amb qualsevol full de càlcul.
Exercicis
Exercici 1: Consultes sobre l'historial de gestor-tasques
Partint de l'historial d'en Bruno tal com apareix a l'apartat 1:
b2e6d3f Bruno 2026-07-31 Corregeix el focus del camp després d'afegir una tasca (app.js) 7c1f4a9 Bruno 2026-07-30 Aplica estil a les tasques completades (estils.css) 3d5b8e1 Bruno 2026-07-29 Afegeix el filtre de tasques pendents (app.js, index.html) c5d9b1e Ana 2026-07-26 Documenta la instal·lació al README (README.md) 4e7f2a9 Ana 2026-07-24 Afegeix l'esborrat de tasques al llistat (app.js) 8b6d3c2 Ana 2026-07-22 Afegeix els estils base del llistat (estils.css, index.html) 1a4c8d6 Ana 2026-07-20 Estructura inicial del gestor de tasques (els 4 fitxers)
Escriu l'ordre exacta per a cada consulta i prediu-ne la sortida:
- Les tres últimes confirmacions, en una línia cadascuna.
- Totes les confirmacions de l'Ana.
- Tot el que s'ha fet entre el 23 i el 27 de juliol, tots dos inclosos.
- Les confirmacions que van tocar
estils.css. - Les confirmacions el missatge de les quals contingui «tasca», sense distingir majúscules.
- Un llistat amb format
hash | data curta | autor | assumpte. - Quantes confirmacions hi ha en total i quantes n'ha fet cada persona.
- El contingut de
README.mdtal com era a4e7f2a9.
Exercici 2: La cerca pickaxe
Crea un repositori amb un historial en què una línia apareix, es mou i desapareix:
mkdir -p ~/practica/pickaxe && cd ~/practica/pickaxe
git init
printf 'function inici() {\n return true;\n}\n' > app.js
git add app.js && git commit -m "Afegeix la funció d'inici"
printf 'function inici() {\n console.log("DEPURACIO: entrant");\n return true;\n}\n' > app.js
git commit -am "Afegeix la traça de depuració"
printf 'function inici() {\n return true;\n}\n\nfunction fi() {\n console.log("DEPURACIO: entrant");\n return false;\n}\n' > app.js
git commit -am "Mou la traça a la funció fi i afegeix-la"
printf 'function inici() {\n return true;\n}\n\nfunction fi() {\n return false;\n}\n' > app.js
git commit -am "Elimina la traça de depuració"- Què retorna
git log --oneline -S "DEPURACIO"? Explica per què apareix cada confirmació i per què en falta alguna. - Què retorna
git log --oneline -G "DEPURACIO"? Compara-ho amb el resultat anterior i explica la diferència. - Què retorna
git log --oneline --grep="DEPURACIO"? I--grep="depuració"? - Escriu l'ordre que mostri el diff de la confirmació exacta en què es va eliminar la traça.
- Redacta en una frase la regla que et permetrà triar entre
-S,-Gi--grepen el futur.
Exercici 3: Navegar per referències
Sobre el repositori de l'exercici 2 (quatre confirmacions, historial lineal):
- Escriu quatre formes diferents de referir-te a la segona confirmació de l'historial (la que va afegir la traça).
- Comprova amb
git rev-parsequeHEAD~2iHEAD^^apunten al mateix objecte. - Mostra el contingut d'
app.jstal com era a la primera confirmació, sense modificar el teu directori de treball. - Mostra únicament els missatges de les dues últimes confirmacions, sense diff.
- Fes servir un rang per llistar només les dues últimes confirmacions i explica per què
HEAD~2..HEADen retorna dues i no tres. - Esbrina quins fitxers va modificar cadascuna de les quatre confirmacions amb una sola ordre.
Solucions
Solució a l'Exercici 1
1. Les tres últimes:
b2e6d3f (HEAD -> main) Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 Aplica estil a les tasques completades 3d5b8e1 Afegeix el filtre de tasques pendents
2. Les de l'Ana:
c5d9b1e Documenta la instal·lació al README 4e7f2a9 Afegeix l'esborrat de tasques al llistat 8b6d3c2 Afegeix els estils base del llistat 1a4c8d6 Estructura inicial del gestor de tasques
3. Entre el 23 i el 27, tots dos inclosos:
Atenció al detall: --until="2026-07-27" s'interpreta com les 00:00 d'aquell dia, així que exclouria les confirmacions del mateix dia 27. Com que aquí volem incloure el dia 27 sencer, hi posem --until="2026-07-28". És un error clàssic que fa «desaparèixer» confirmacions de l'últim dia del rang.
4. Les que van tocar estils.css:
Nota: 1a4c8d6 va crear el fitxer, així que en un historial real també hi apareixeria. A l'enunciat s'indica que la confirmació inicial contenia els quatre fitxers, de manera que la sortida completa seria de tres entrades.
5. Missatges amb «tasca», sense distingir majúscules:
b2e6d3f Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 Aplica estil a les tasques completades 3d5b8e1 Afegeix el filtre de tasques pendents 4e7f2a9 Afegeix l'esborrat de tasques al llistat 1a4c8d6 Estructura inicial del gestor de tasques
Cinc de les set. En queden fora c5d9b1e («Documenta la instal·lació al README») i 8b6d3c2 («Afegeix els estils base del llistat»), els missatges de les quals no contenen la paraula.
6. Format personalitzat:
b2e6d3f | 2026-07-31 | Bruno Salas | Corregeix el focus del camp després d'afegir una tasca 7c1f4a9 | 2026-07-30 | Bruno Salas | Aplica estil a les tasques completades 3d5b8e1 | 2026-07-29 | Bruno Salas | Afegeix el filtre de tasques pendents c5d9b1e | 2026-07-26 | Ana Ferrer | Documenta la instal·lació al README 4e7f2a9 | 2026-07-24 | Ana Ferrer | Afegeix l'esborrat de tasques al llistat 8b6d3c2 | 2026-07-22 | Ana Ferrer | Afegeix els estils base del llistat 1a4c8d6 | 2026-07-20 | Ana Ferrer | Estructura inicial del gestor de tasques
7. Totals:
8. El README a 4e7f2a9:
Mostra el contingut del fitxer tal com era en aquella confirmació, sense tocar el directori de treball. Si el volguéssim desar a part:
Solució a l'Exercici 2
1. Amb -S:
Dues confirmacions. -S busca canvis en el nombre d'aparicions de la cadena:
9b3e5d7: va passar de 0 aparicions a 1. Va canviar → hi apareix.1f4c8a2: va passar d'1 a 0. Va canviar → hi apareix.
Hi falta 7a2d6f9 («Mou la traça a la funció fi i afegeix-la»). I aquí hi ha el matís que cal entendre: en aquella confirmació la traça es va moure d'inici() a fi(), així que continua apareixent una sola vegada. Com que el recompte no varia (1 → 1), -S la considera irrellevant i no la mostra.
2. Amb -G:
1f4c8a2 Elimina la traça de depuració 7a2d6f9 Mou la traça a la funció fi i afegeix-la 9b3e5d7 Afegeix la traça de depuració
Tres confirmacions. -G no compta aparicions: mira si el diff de la confirmació conté alguna línia afegida o eliminada que casi amb l'expressió. A 7a2d6f9 hi ha una línia amb DEPURACIO eliminada i una altra d'afegida, així que sí que hi apareix.
Aquesta és exactament la diferència entre totes dues opcions, i l'exercici l'aïlla en la seva forma més pura.
3. Amb --grep:
Cap, perquè --grep busca al missatge, i cap missatge no conté la paraula en majúscules.
Dues: les que porten aquella paraula al missatge. Que coincideixin amb el resultat de -S és pura casualitat de l'exemple; es deu al fet que els missatges descriuen bé el que fan.
4. El diff de l'eliminació:
O, més directe i més llegible, localitzar el commit i mostrar-lo:
commit 1f4c8a2...
Elimina la traça de depuració
diff --git a/app.js b/app.js
@@ -4,4 +4,3 @@ function inici() {
function fi() {
- console.log("DEPURACIO: entrant");
return false;
}Una manera robusta d'encadenar-ho, sense conèixer el hash per endavant:
que mostra la confirmació més recent en què va canviar el recompte d'aquella cadena: precisament l'eliminació.
5. La regla:
--grepbusca al missatge («qui va dir que feia això?»);-Sbusca quan va aparèixer o desaparèixer un text al codi («d'on va sortir aquesta línia?»);-Gbusca quines confirmacions van tocar línies que casen amb un patró, moviments inclosos («qui ha rondat per aquí?»).
Solució a l'Exercici 3
1. Quatre formes de referir-se a la segona confirmació (amb HEAD a la quarta):
git show 9b3e5d7 # 1. hash abreujat
git show HEAD~2 # 2. dues generacions enrere
git show HEAD^^ # 3. el pare del pare
git show HEAD~1^ # 4. el pare de l'anteriorI n'hi ha més: el hash complet, main~2, @~2… Totes resolen al mateix objecte.
2. Comprovació:
git rev-parse HEAD~2
# → 9b3e5d7f4a2c8e1b5d3f7a9c2e6b4d8f1a3c5e7b
git rev-parse HEAD^^
# → 9b3e5d7f4a2c8e1b5d3f7a9c2e6b4d8f1a3c5e7bHashos idèntics. En un historial lineal ~n i n símbols ^ són equivalents, perquè cada commit té un únic pare i «triar el primer pare» i «retrocedir una generació» són la mateixa operació. La diferència només emergeix a les fusions.
3. El fitxer a la primera confirmació:
git show <commit>:<ruta> llegeix de l'historial i escriu a la sortida estàndard. No modifica res, a diferència de git restore --source=..., que sí que sobreescriuria el fitxer del disc.
4. Només els missatges de les dues últimes:
O, si prefereixes la vista completa sense el diff:
5. El rang:
Dues confirmacions, no tres, perquè l'extrem esquerre del rang queda exclòs. a..b significa «tot el que és assolible des de b que no ho sigui des d'a», i HEAD~2 és assolible des d'ell mateix, així que es descarta. La manera de llegir-ho és: «el que ha passat després de HEAD~2».
Si també volguessis incloure HEAD~2, hauries d'escriure HEAD~3..HEAD.
6. Fitxers modificats per cada confirmació:
1f4c8a2 Elimina la traça de depuració M app.js 7a2d6f9 Mou la traça a la funció fi i afegeix-la M app.js 9b3e5d7 Afegeix la traça de depuració M app.js 4c1e8b5 Afegeix la funció d'inici A app.js
Les tres últimes confirmacions modifiquen app.js (M) i la primera l'afegeix (A), cosa que és coherent: era el root-commit i el fitxer no existia abans.
Conclusió
Amb aquesta lliçó tanquem el cicle bàsic de Git i el mòdul 2. Recapitulant el que hem après aquí:
git logrecorre l'historial cap enrere des deHEAD, en ordre cronològic invers, seguint els enllaços als pares.- Els formats canvien completament el que veus:
--onelineper a la vista de treball,--graphper a l'estructura (imprescindible tan bon punt hi hagi branques),--statper a l'abast de cada canvi i-pper al diff complet. --pretty=format:permet dissenyar la teva pròpia sortida amb marcadors com%h,%an,%ari%s, i val la pena desar-la com a àlies.- Els filtres converteixen
git logen un cercador:-nper quantitat,--since/--untilper data,--authorper persona,--grepper missatge i-- <ruta>per fitxer. Filtres de tipus diferent es combinen amb I lògic. - La cerca «pickaxe» és la joia amagada:
-Stroba quan va aparèixer o desaparèixer un text al codi, i-Gquines confirmacions van tocar línies que casen amb un patró. No confonguis cap de les dues amb--grep, que mira el missatge. git showinspecciona una confirmació concreta —metadades i diff— i amb la sintaxi<commit>:<ruta>recupera qualsevol fitxer tal com era en qualsevol moment del passat.- Referir-se a una confirmació es pot fer per hash (complet o abreujat), per referència simbòlica (
HEAD,main,origin/main, una etiqueta) o per navegació relativa:~retrocedeix generacions i^tria entre pares. Els rangsa..bexclouen l'extrem esquerre.
El que portes del mòdul 2
Has recorregut el cicle complet de treball amb Git en solitari:
- Crear el repositori (
git init) o unir-te a un d'existent (git clone). - Treballar seguint el cicle editar → preparar → confirmar, amb
git statuscom a brúixola. - Triar amb precisió què entra a cada confirmació, fins i tot a nivell de fragment amb
git add -p. - Revisar els canvis amb
git diffabans de registrar-los. - Consultar el passat amb
git logigit show.
Amb això ja pots fer servir Git de manera productiva en qualsevol projecte propi. Però hi ha un problema esperant.
El que ve: l'equip comença a trepitjar-se
Fixa't en la situació real en què són l'Ana i en Bruno ara mateix. Tots dos han estat treballant sobre main, cadascú al seu portàtil, sense coordinar-se. L'Ana ha afegit el comptador de tasques i el marcatge de completades; en Bruno ha afegit el filtre de pendents i ha tocat els mateixos fitxers. Cap dels dos no ha vist la feina de l'altre.
Quan intentin ajuntar tot això, es trobaran amb dues versions diferents d'app.js que han evolucionat per separat des del mateix punt de partida. I això és només amb dues persones i una setmana de feina: quan la Carla s'incorpori des de Windows i hi hagi tres línies de desenvolupament simultànies, treballar tots sobre main serà insostenible.
A més, hi ha un problema més subtil. Ara mateix, si l'Ana vol provar una idea arriscada, no té on fer-ho: qualsevol cosa que confirmi va directa a l'única línia del projecte. I si a mitja tasca urgent apareix una fallada crítica, ha d'abandonar el que està fent o confirmar-ho a mitges.
La resposta a tot això són les branques, i són la característica que va convertir Git en l'estàndard de la indústria. Al mòdul 3: Branques i Fusió veurem què és realment una branca (spoiler: ja ho saps, és un fitxer amb un hash a dins, com vam comprovar en crear el primer commit), com crear-les i moure's entre elles, com fusionar la feina de diverses persones, quines estratègies fa servir Git per fer-ho, com resoldre els conflictes quan dues persones toquen la mateixa línia, i com mantenir endreçat un repositori amb moltes branques vives.
Tot el que has après en aquest mòdul —les tres zones, l'àrea de preparació, el diff, l'historial— continua sent vàlid exactament igual. Només que a partir d'ara hi haurà més d'una línia de treball alhora.
Dominant Git: De Principiant a Avançat
Mòdul 1: Introducció a Git
- Què és Git?
- Instal·lant Git
- Terminologia Bàsica de Git
- El Model de Dades de Git
- Configurant Git
- Configuració Inicial
Mòdul 2: Operacions Bàsiques de Git
- Creant un Repositori
- Clonant un Repositori
- Flux de Treball Bàsic de Git
- Preparant i Confirmant Canvis
- Inspeccionant Canvis amb git diff
- Visualitzant l'Historial de Confirmacions
Mòdul 3: Branques i Fusió
- Entenent les Branques
- Creant i Canviant Branques
- Fusionant Branques
- Estratègies de Fusió
- Resolent Conflictes de Fusió
- Gestió de Branques
Mòdul 4: Treballant amb Repositoris Remots
- Entenent els Repositoris Remots
- Afegint un Repositori Remot
- Autenticació amb Repositoris Remots
- Obtenint i Baixant Canvis
- Enviant Canvis
- Rastrejant Branques
Mòdul 5: Operacions Avançades de Git
- Rebase
- Rebase Interactiu
- Cherry-Picking de Confirmacions
- Desant Canvis Temporals
- Etiquetant Confirmacions
- Revertint Confirmacions
Mòdul 6: Eines i Tècniques de Git
- Usant Git Hooks
- Git Bisect
- Git Blame
- Git Log i Àlies
- Submòduls de Git
- Múltiples Còpies de Treball amb git worktree
Mòdul 7: Estratègies de Col·laboració i Flux de Treball
- Forks i Pull Requests
- Revisions de Codi amb Git
- Flux de Treball Git Flow
- GitHub Flow
- Trunk Based Development
- Integració Contínua amb Git
Mòdul 8: Bones Pràctiques i Consells de Git
- Escrivint Bons Missatges de Confirmació
- Mantenint un Historial Net
- Ignorant Fitxers amb .gitignore
- Atributs de Fitxer amb .gitattributes
- Bones Pràctiques de Seguretat
- Consells de Rendiment
Mòdul 9: Resolució de Problemes i Depuració
- Problemes Habituals de Git
- Desfent Canvis
- Resolent Divergències amb el Remot
- Recuperant Confirmacions Perdudes
- Tractant amb Repositoris Corruptes
- Tècniques Avançades de Depuració
