La lliçó anterior va deixar en Diego amb la seva pull request oberta i l'Ana a punt de revisar-la. Ara toca el que passa dins d'aquest canal: la revisió de codi.
Gairebé tothom revisa codi de la mateixa manera: obre la pestanya de canvis al navegador, fa scroll, deixa tres comentaris sobre noms de variables i aprova. Això no és revisar; és fullejar. Una revisió de debò exigeix entendre el problema, entendre la solució i, moltes vegades, executar el codi. I per a això cal Git, no pas un navegador.
Aquesta lliçó té dues meitats. La primera és tècnica: quines ordres fer servir per revisar bé, incloent-hi una —git range-diff— que resol un problema que tothom pateix i gairebé ningú no sap que té solució. La segona és humana: què mirar, en quin ordre, com comentar sense desmoralitzar i què fer quan dues persones no es posen d'acord. Totes dues importen igual.
Contingut
- Per a què serveix realment una revisió (i per a què no)
- El diff correcte per revisar: per què tres punts
- Portar la branca i examinar-la amb Git
- Revisar commit a commit
git range-diff: què ha canviat des de la revisió anterior- Revisió per correu:
request-pull,format-patchiam - Què mirar, per ordre de prioritat
- Com comentar bé
- La mida importa: l'efecte de la mida de la PR
- Aprovar, demanar canvis i gestionar els desacords
- Per a què serveix realment una revisió (i per a què no)
Abans de les ordres, el propòsit. Una revisió de codi persegueix tres objectius, i no són al mateix pla:
1. Detectar defectes. L'obvi. Un segon parell d'ulls troba el cas límit que no vas contemplar, la condició invertida, la variable que es llegeix abans d'assignar-se. És real, però —i això sorprèn molta gent— no és el benefici principal. Les proves automàtiques i el CI (lliçó 07-06) atrapen més defectes que qualsevol revisió humana, i ho fan sense cansar-se.
2. Difondre coneixement. Aquest sí que és el gran. Quan l'Ana revisa el canvi de la Carla a app.js, dues persones acaben entenent aquella part del codi en comptes d'una. Quan en Diego, que ve de fora, llegeix els comentaris de l'Ana, aprèn com es fan les coses en aquest projecte. La revisió és el mecanisme pel qual un equip deixa de tenir illes de coneixement on només una persona sap com funciona alguna cosa. Aquell «només en Bruno entén el mòdul de sincronització» és un risc operatiu, i la revisió és la cura barata.
3. Mantenir la coherència. Un codi on cada fitxer sembla escrit per una persona diferent és més car de mantenir que un d'uniforme, encara que les decisions individuals siguin pitjors. La revisió és on es negocia aquesta uniformitat.
I ara, per a què no serveix:
| No és feina de la revisió | Qui ho hauria de fer |
|---|---|
| Comprovar la indentació i el format | Un formatador automàtic (Prettier, gofmt, Black) |
| Detectar variables sense fer servir, imports morts | El linter |
| Executar la bateria de proves | El CI (lliçó 07-06) |
| Comprovar el format del missatge de commit | El hook commit-msg (lliçó 06-01) |
| Verificar que compila | El CI |
La regla és demolidora en la seva simplicitat: si una màquina ho pot comprovar, que ho comprovi la màquina. Cada comentari humà sobre un espai en blanc és un comentari que no s'ha dedicat a la lògica, i a sobre genera ressentiment. Si el teu equip discuteix sobre cometes simples o dobles a les revisions, el problema no són les cometes: és que falta un formatador al pre-commit.
Aquesta idea té una conseqüència directa en com es dissenya el procés: les eines automàtiques van primer, al hook local o al CI, i la revisió humana comença on elles acaben. Si el CI està en vermell, no revisis: no té sentit gastar atenció humana en una cosa que ni tan sols passa les proves.
- El diff correcte per revisar: per què tres punts
Aquest apartat és el cor tècnic de la lliçó, i mereix que el llegeixis a poc a poc.
L'Ana vol veure «el que ha fet en Diego». Sembla trivial. No ho és.
Recordem la situació. En Diego va partir de main al commit C3. Mentre treballava, l'equip va integrar dos commits més a main. El graf (lliçó 03-01) és aquest:
gitGraph commit id: "C1" commit id: "C2" commit id: "C3" branch correccio/reordenar checkout correccio/reordenar commit id: "D1" commit id: "D2" checkout main commit id: "C4" commit id: "C5"
Ara les dues opcions:
git diff main..correccio/reordenar (dos punts)
Els dos punts, a git diff, són decoratius: git diff A..B és exactament el mateix que git diff A B. Compara les dues puntes: l'arbre de C5 contra l'arbre de D2.
Què mostra, això? La suma de dues coses diferents:
- Els canvis d'en Diego (
D1,D2), en el seu sentit correcte. - Els canvis de
C4iC5, del revés — perquè des del punt de vista deC5, la branca d'en Diego «ha desfet» el que van fer l'Ana i la Carla.
El resultat és un diff contaminat. L'Ana veu línies eliminades que ella mateixa va escriure ahir i que en Diego no ha tocat mai. És soroll pur.
git diff main...correccio/reordenar (tres punts)
Els tres punts a git diff volen dir una cosa molt concreta:
git diff A...Bequival agit diff $(git merge-base A B) B
És a dir: compara des de l'ancestre comú. Al nostre graf, l'ancestre comú de main i la branca d'en Diego és C3. Per tant, git diff main...correccio/reordenar compara C3 amb D2.
I això és exactament el que ha fet en Diego, i res més. Els commits C4 i C5 no hi apareixen, perquè C3 és anterior a ells.
Comprova-ho tu mateix:
# Aquestes dues ordres donen el mateix resultat
git diff main...correccio/reordenar
git diff $(git merge-base main correccio/reordenar) correccio/reordenarLa taula resum, que convé memoritzar:
| Forma | Què compara | Quan fer-la servir |
|---|---|---|
git diff A B |
Punta d'A contra punta de B | Comparar dos estats qualssevol |
git diff A..B |
Idèntic a l'anterior | Mai; només confon |
git diff A...B |
Ancestre comú d'A i B contra punta de B | Revisar una branca |
Avís important: a
git logels punts volen dir una altra cosa. Aquest és un dels paranys més pesats de Git, i ja el vam esmentar a la lliçó 06-04. Agit log,A..Bés «els commits de B que no són a A» (el que vols per revisar) iA...Bés la diferència simètrica: els commits exclusius de cada costat. És a dir, per revisar es fan servir tres punts adiffi dos punts alog. No és intuïtiu. És així.
La raó de fons és que diff opera sobre arbres (dues fotos per comparar) i log opera sobre conjunts de commits. Són operacions diferents que reutilitzen la mateixa notació amb semàntiques diferents. Una decisió històrica desafortunada, però és la que hi ha.
I aquí hi ha la connexió important: quan la plataforma t'ensenya el diff d'una pull request, t'està ensenyant el de tres punts. Per això de vegades veus al web un diff net i, en fer git diff main branca en local, hi apareixen canvis aliens. No és un error de la plataforma: és que feies servir l'ordre equivocada.
- Portar la branca i examinar-la amb Git
L'Ana comença per portar-se la feina d'en Diego amb la referència de PR de la lliçó anterior:
Amb això ja pot treballar sense canviar de branca, perquè totes les ordres d'inspecció accepten referències:
a7c2e91 Repinta nomes si l'ordre ha canviat b3f1a7d Reordena la llista en marcar una tasca com a completada
Dos punts, perquè és log. Llegeix: «els commits de la branca que no són a main».
# 2. Quins fitxers toca i quant? La foto de conjunt, abans de llegir res.
git diff --stat main...revisio/pr-42app.js | 24 ++++++++++++++++-------- estils.css | 3 +++ 2 files changed, 19 insertions(+), 8 deletions(-)
Aquesta és sempre la primera ordre que cal executar. En deu segons saps si tens al davant una revisió de cinc minuts o d'una hora, i si l'abast coincideix amb el que prometia la descripció. Si la PR diu «corregeix la reordenació» i toca divuit fitxers, ja tens el teu primer comentari.
L'opció -U10 (lliçó 02-05) mostra deu línies de context en comptes de tres. En una revisió és gairebé sempre el que vols: el defecte sol ser a la interacció entre el que ha canviat i el que no.
Si algú ha reindentat una funció en modificar-la, -w (equivalent a --ignore-all-space) revela el canvi real sota el soroll. Combinat amb --word-diff, molt útil per a canvis de documentació:
# 5. Detectar codi mogut en comptes de reescrit
git diff --color-moved=dimmed-zebra main...revisio/pr-42--color-moved pinta d'un altre color els blocs que simplement s'han mogut de lloc, distingint-los dels que s'han escrit de nou. En una PR de refactorització, la diferència entre «ha mogut 200 línies» i «ha reescrit 200 línies» canvia del tot el que cal revisar.
I, és clar, executar-lo. Aquí és on git worktree (lliçó 06-06) es guanya el sou:
git worktree add ../revisio-42 revisio/pr-42
cd ../revisio-42
# obrir index.html, reproduir els passos de la descripció de la PRL'Ana comprova l'errada original, aplica el canvi, comprova que desapareix. Res d'això no es veu en un diff.
- Revisar commit a commit
Una PR ben construïda (lliçó 07-01) té commits que expliquen una història. Aprofita-ho: revisar tres commits de cinquanta línies cadascun és moltíssim més fàcil que revisar-ne un de cent cinquanta.
--reverseels presenta del més antic al més recent, que és l'ordre en què es van pensar.-phi afegeix el diff de cadascun.
Per saltar entre ells sense sortir del terminal:
# Només els missatges, per fer-se el mapa
git log --reverse --format='%h %s%n%n%b' main..revisio/pr-42
# El diff d'un commit concret
git show b3f1a7dUna altra vista molt útil: qui ha tocat abans aquestes línies. Si el canvi d'en Diego modifica una funció que en Bruno va escriure fa dues setmanes per una raó concreta, convé saber-ho abans d'aprovar:
I git blame amb les opcions del mòdul 6:
Fixa't en el main del final: blame sobre la versió anterior al canvi, per entendre el context que en Diego es va trobar.
Consell de mètode. Llegeix primer la descripció de la PR, després el
--stat, després els missatges dels commits, i només llavors el codi. Arribar al diff sabent què esperes trobar converteix la revisió en una verificació d'hipòtesis en comptes d'una lectura a cegues. És diverses vegades més ràpid i detecta més coses.
git range-diff: què ha canviat des de la revisió anterior
git range-diff: què ha canviat des de la revisió anteriorAquest apartat és la joia de la lliçó.
Situació: l'Ana va revisar la PR d'en Diego i va demanar tres canvis. En Diego els va aplicar i, a més, va fer git rebase upstream/main perquè main havia avançat. Ara envia amb --force-with-lease i la PR s'actualitza.
L'Ana torna. I es troba amb un problema real: tots els commits tenen hashos nous. El rebase els va reescriure (lliçó 05-01). La plataforma li ofereix «veure els canvis des de la teva última revisió», però sovint es rendeix amb un missatge de l'estil «l'autor ha forçat l'enviament, no es pot mostrar la comparació». L'Ana no sap si en Diego només va aplicar els seus tres suggeriments o si de passada va canviar altres coses. La seva única opció aparent és revisar-ho tot un altre cop.
git range-diff resol exactament això:
git range-diffcompara dues sèries de commits i et diu, per a cadascun, si s'ha mantingut igual, si ha desaparegut, si és nou o què ha canviat a dins. És un diff de diffs.
La manera de fer-lo servir requereix haver desat la versió anterior. L'Ana, previsora, ho va fer abans d'acabar la seva primera revisió:
# A la primera revisió, l'Ana desa una referència del que va veure
git branch revisio/pr-42-v1 revisio/pr-42Ara, després de l'actualització d'en Diego:
git fetch origin pull/42/head:revisio/pr-42-v2
# Comparar les dues versions de la sèrie
git range-diff main...revisio/pr-42-v1 main...revisio/pr-42-v2La sintaxi amb tres punts és una drecera. La forma completa és de tres arguments i de vegades és més clara:
git range-diff <base-antiga>..<punta-antiga> <base-nova>..<punta-nova>
git range-diff C3..revisio/pr-42-v1 C7..revisio/pr-42-v2La sortida:
1: b3f1a7d = 1: 9e4c2a8 Reordena la llista en marcar una tasca com a completada
2: a7c2e91 ! 2: 4f8b1d3 Repinta nomes si l'ordre ha canviat
@@ app.js: function marcaCompletada(id) {
const ordrePrevi = llistaOrdenada.map(t => t.id).join(',');
actualitzaEstat(id, true);
- if (true) {
+ if (ordrePrevi !== llistaOrdenada.map(t => t.id).join(',')) {
renderitzaLlista();
}
3: -------- > 3: 7a1c5e9 Afegeix prova de reordenacioI ara la clau: com es llegeix aquesta sortida.
| Marca | Significat |
|---|---|
= |
El commit és equivalent: mateix contingut, encara que el hash canviï pel rebase |
! |
El commit ha canviat; a sota es mostra el diff de les seves diferències |
< |
El commit era a la sèrie antiga i ja no hi és |
> |
El commit és nou a la sèrie |
A l'exemple, l'Ana llegeix en cinc segons: el primer commit no ha canviat (no cal rellegir-lo), el segon ha canviat exactament en la condició que ella va demanar corregir, i n'hi ha un tercer de nou que afegeix una prova. Revisió acabada. Sense range-diff, hauria rellegit cent cinquanta línies.
Detalls pràctics que fan que funcioni millor:
# Diff de diffs acolorit i més llegible
git range-diff --creation-factor=95 main...revisio/pr-42-v1 main...revisio/pr-42-v2--creation-factor (per defecte 60) controla quant s'han d'assemblar dos commits per considerar-los «el mateix commit modificat» en comptes de «un d'esborrat i un altre de nou». Si range-diff et mostra un munt de < i > quan esperaves !, apuja el valor.
Aquest ús és igual de valuós: abans de forçar l'enviament després d'un rebase, comprova que no has espatllat res sense voler. @{u} és l'upstream de la branca (lliçó 04-06), és a dir, el que hi ha publicat; HEAD és el que estàs a punt de publicar. Si surt tot = llevat del que volies canviar, endavant amb confiança. Si hi apareix un commit modificat que no esperaves, acabes de detectar un conflicte mal resolt durant el rebase.
I un tercer ús: comparar com es va aplicar una sèrie de commits en dues branques diferents, per exemple després d'un cherry-pick massiu a una branca de manteniment (lliçó 05-03).
git range-diffexisteix des de Git 2.19 (2018) i continua sent poc conegut. És probablement l'ordre amb millor relació entre el que resol i el que es fa servir. Si t'endús una sola cosa tècnica d'aquesta lliçó, que sigui aquesta.
- Revisió per correu:
request-pull, format-patch i am
request-pull, format-patch i amAbans que existissin les plataformes web, i encara avui en projectes com el nucli de Linux, Git, PostgreSQL o Buildroot, la revisió passa en una llista de correu. Val la pena conèixer el mecanisme per tres raons: explica d'on ve l'expressió «pull request», funciona sense dependre de cap empresa, i apareix en projectes importants amb els quals potser voldràs col·laborar.
git request-pull: la pull request original
Els tres arguments són: el punt de partida (una etiqueta o commit que el destinatari ja té), la URL des d'on es pot portar la feina, i la branca.
La sortida és un text llest per enganxar en un correu:
The following changes since commit 3f2a91c8d4b7e0a5c9f2d6b3a8e1c4f7d0b3a6e9:
Publica la versio 2.3.0 (2026-07-12 09:14:22 +0200)
are available in the Git repository at:
https://git.exemple.cat/drueda/gestor-tasques.git correccio/reordenar
for you to fetch changes up to a7c2e91f4d8b1c5e9a2f7d0b3c6e9a1f4d8b1c5e:
Repinta nomes si l'ordre ha canviat (2026-07-28 17:03:45 +0200)
----------------------------------------------------------------
Diego Rueda (2):
Reordena la llista en marcar una tasca com a completada
Repinta nomes si l'ordre ha canviat
app.js | 24 ++++++++++++++++--------
estils.css | 3 +++
2 files changed, 19 insertions(+), 8 deletions(-)Això és literalment una «pull request»: un missatge que diu «fes pull d'aquí». Els botons de les plataformes automatitzen aquest correu. Ara el nom té sentit.
format-patch i am: el model del nucli
Quan el destinatari no pot o no vol fer fetch des del teu servidor, s'envien els canvis com a pedaços dins del correu mateix:
0001-Reordena-la-llista-en-marcar-una-tasca-com-a-complet.patch 0002-Repinta-nomes-si-l-ordre-ha-canviat.patch
Cada fitxer és un correu complet: capçaleres, autor, data, missatge del commit i el diff. Opcions habituals:
# Amb una carta de presentació (el "0000-cover-letter.patch")
git format-patch --cover-letter -o /tmp/pedacos main..correccio/reordenar
# Segona ronda després de la revisió, marcada com a v2
git format-patch -v2 --cover-letter -o /tmp/pedacos main..correccio/reordenarLa carta de presentació és l'equivalent a la descripció de la PR, i el -v2 és com s'indica que aquesta és la segona versió de la sèrie després dels comentaris rebuts. En aquests projectes, git range-diff s'inclou habitualment a la carta de presentació de la v2, perquè els revisors vegin què va canviar respecte de la v1. És precisament el flux per al qual es va dissenyar l'ordre.
De l'altre costat, qui rep els pedaços els aplica amb git am (apply mailbox):
git am crea un commit per pedaç, conservant l'autor original, la seva data i el seu missatge. Aquesta és la diferència crucial amb git apply, que només aplica els canvis al directori de treball sense crear res. Si un pedaç no aplica netament:
git am --show-current-patch=diff # veure què falla
git am --3way # reintentar amb fusió a tres bandes
git am --skip # saltar-se aquest pedaç
git am --abort # cancel·lar tota la sèriePer enviar-los per correu existeix git send-email, que parla directament amb un servidor SMTP. No el desenvoluparem: si algun dia col·labores amb un projecte d'aquest tipus, la seva documentació explicarà la configuració concreta.
| Model | Canal | Eina | Avantatge | Inconvenient |
|---|---|---|---|---|
| Plataforma | Web | Pull request | Accessible, integrada amb CI | Depèn d'un proveïdor |
request-pull |
Correu + fetch |
git request-pull |
Descentralitzat, sense intermediaris | Requereix servidor propi |
| Pedaços | Correu | format-patch / am |
No requereix cap servidor | Corba d'aprenentatge alta |
- Què mirar, per ordre de prioritat
Aquí comença la meitat humana. L'error més comú d'un revisor novell és començar pel més petit: comenta el nom d'una variable a la línia 3, s'hi embolica, i mai no arriba a adonar-se que la solució sencera està mal plantejada.
Revisa en aquest ordre, i no baixis de nivell fins a haver tancat l'anterior:
Nivell 1 — Correcció: fa el que diu?
- Resol realment el problema descrit? L'has reproduït?
- Casos límit: llista buida, valors nuls, textos llarguíssims, caràcters estranys?
- Condicions de cursa, estat compartit, ordre d'esdeveniments?
- Tractament d'errors, o el
catchés buit? - Hi ha proves? Proven el comportament o la implementació?
- Seguretat: entrades sense validar, dades d'usuari inserides sense escapar, secrets al codi? (mòdul 8)
Si alguna cosa falla aquí, atura't i comenta-ho. No continuïs revisant noms de variables de codi que desapareixerà.
Nivell 2 — Disseny: és la manera correcta de resoldre-ho?
- Encaixa amb l'arquitectura existent o introdueix un patró nou sense justificació?
- És al lloc correcte? Hauria de viure a
components-uien comptes de aapp.js? - Duplica alguna cosa que ja existeix?
- És més complicat del que cal? I massa genèric «per si de cas»?
- Trenca alguna interfície de la qual depengui un altre codi?
Aquest nivell és el més valuós i el que més es descuida, perquè exigeix entendre el sistema. També és el que costa més car de corregir després: un problema de disseny detectat en revisió són dues hores; el mateix problema detectat sis mesos més tard és una refactorització.
Nivell 3 — Llegibilitat: ho entendrà algú d'aquí a un any?
- Els noms diuen el que les coses són?
- Hi ha comentaris on calen —el perquè, no el què— i absència de comentaris obvis?
- Les funcions fan una sola cosa?
- La complexitat està justificada o hi ha un
ifimbricat a quatre nivells? - Els missatges dels commits expliquen el perquè? (lliçó 08-01)
Nivell 4 — Estil: convencions
I aquí, recorda l'apartat 1: si el linter ho pot comprovar, no ho comentis. Aquest nivell hauria d'estar pràcticament buit en un projecte amb bones eines. Si no ho està, la conclusió correcta no és «cal comentar més», sinó «cal configurar el formatador».
- Com comentar bé
Una revisió mal escrita fa més mal que cap revisió. Quatre regles.
Regla 1: sobre el codi, no sobre la persona
| En comptes de | Escriu |
|---|---|
| «No has controlat el cas de llista buida» | «Si tasques arriba buit, tasques[0] dóna undefined aquí» |
| «Això està malament» | «Això falla quan el títol té cometes: es trenca l'innerHTML» |
| «Per què ho has fet així?» | «Què t'ha portat a aquest enfocament? Ho pregunto perquè a renderitzaLlista fem servir l'altre i em pregunto si hi ha una raó» |
No és qüestió de suavitzar per educació: és que la formulació centrada en el codi inclou la informació necessària per arreglar-ho, i la centrada en la persona no. «Està malament» no es pot accionar; «falla amb cometes al títol» sí.
Regla 2: distingeix el bloquejant de l'opcional
El revisor sap quins dels seus comentaris són imprescindibles i quins són preferències. L'autor no ho sap si no li ho dius. Marcar-ho explícitament estalvia moltíssima fricció, i hi ha una convenció força estesa:
| Prefix | Significat | Bloqueja? |
|---|---|---|
bloquejant: |
Cal arreglar-ho abans d'integrar | Sí |
pregunta: |
No entenc alguna cosa; pot ser que estigui bé | Depèn de la resposta |
suggeriment: |
Crec que seria millor així, però és decisió teva | No |
nit: (de nitpick) |
Detall menor, agafa'l o deixa'l | No |
elogi: |
Això està ben resolt | No |
Exemple sobre la PR d'en Diego:
bloquejant: si `tasques` està buit, `tasques[0].id` llança una excepció
a la línia 47. Cal la comprovació abans de l'accés.
suggeriment: `renderitzaLlista()` recorre l'array dues vegades (línies 52 i 58).
Es podria fer en una sola passada, tot i que amb llistes de menys
de mil elements no crec que es noti. Tu decideixes.
nit: `l` com a nom de variable a la línia 61. `llistaOrdenada`?
elogi: bona idea comparar l'ordre abans de repintar. No se m'havia
acudit i evita el parpelleig.L'últim punt no és farciment. Comentar el que està bé no és cortesia buida: li diu a l'autor què ha de continuar fent, i en un equip on només es comenta el dolent la revisió es viu com un càstig.
Regla 3: suggereix codi quan sigui més ràpid que explicar-ho
Les plataformes permeten proposar un canvi concret que l'autor accepta amb un clic. Si el teu comentari ocuparà tres paràgrafs explicant com reescriure quatre línies, escriu les quatre línies.
Regla 4: revisa aviat
Una PR que espera dos dies bloqueja el seu autor, acumula conflictes amb main i perd context (l'autor ja ha oblidat per què va fer el que va fer). Molts equips acorden un compromís explícit de l'estil «tota PR rep una primera resposta abans de 24 hores». El compromís és respondre, no necessàriament aprovar: un «m'ho miro demà al matí» ja desbloqueja la planificació de l'altra persona.
- La mida importa: l'efecte de la mida de la PR
Si d'aquesta lliçó només s'apliqués una cosa a l'equip, hauria de ser aquesta.
La capacitat d'un revisor humà no escala amb la mida del canvi: s'ensorra. Els estudis sobre revisió de codi fa dècades que apunten en la mateixa direcció, i l'experiència de qualsevol que hagi revisat molt ho confirma:
| Línies canviades | Què passa a la pràctica | Defectes detectats |
|---|---|---|
| < 50 | Es revisa sencera i amb atenció, en minuts | Molt alta |
| 50 – 200 | Revisió sòlida i realista. El punt òptim | Alta |
| 200 – 400 | Es comença bé i s'acaba en diagonal | Mitjana |
| 400 – 1000 | Es revisa la primera part; la resta es fulleja | Baixa |
| > 1000 | «Em sembla bé» en quatre minuts | Gairebé nul·la |
Hi ha una paradoxa cruel amagada aquí: com més gran és un canvi, més risc té i menys es revisa. Una PR de mil cinc-centes línies, que és justament la que més atenció necessitaria, és la que rep una aprovació en quatre minuts perquè ningú no té el temps ni l'energia per fer-ho bé.
I hi ha un segon efecte, menys evident: el nombre de comentaris no creix amb la mida, decreix. Un revisor deixa deu comentaris en una PR de cent línies i tres en una de mil, perquè a la segona es rendeix. L'autor interpreta el silenci com una aprovació.
Què fer amb un canvi gran de debò
Alguns canvis són grans per naturalesa. Estratègies, per ordre de preferència:
- Trossejar en diverses PRs encadenades. Cadascuna completa, coherent i revisable per separat; cadascuna parteix de l'anterior. És més feina per a l'autor i moltíssim millor per a l'equip.
- Separar el mecànic del substancial. Una PR amb el reanomenament massiu o el reformatatge (revisable en dos minuts amb
git diff -w) i una altra amb el canvi de comportament. I apunta el commit del reformatatge a.git-blame-ignore-revs(lliçó 06-03). - Revisar commit a commit, si l'autor els va construir bé (apartat 4).
- Revisió en parella, en directe. Per a canvis arquitectònics grans, mitja hora de conversa ret més que dos-cents comentaris asíncrons.
I una recomanació a l'autor: si la teva PR serà inevitablement gran, avisa-ho a la descripció i suggereix un ordre de lectura. «Comença per app.js línies 40-90, que és el canvi real; la resta és propagació mecànica» estalvia mitja hora al revisor.
- Aprovar, demanar canvis i gestionar els desacords
Els tres veredictes
| Veredicte | Quan | Efecte |
|---|---|---|
| Aprovar | No hi ha res bloquejant | Habilita la integració |
| Demanar canvis | Hi ha almenys un bloquejant: |
Sol impedir la integració fins a resoldre'l |
| Comentar | Has opinat però no vols decidir | Neutre |
Dos matisos sobre «aprovar» que eviten molta fricció:
- Aprovar no vol dir «és perfecte», vol dir «això millora l'estat actual del projecte i no introdueix problemes». Perseguir la perfecció a cada PR paralitza l'equip i crema la gent.
- Es pot aprovar amb comentaris menors. És la sortida sana per als
nit:i elssuggeriment:: aproves, l'autor decideix si aplicar-los, i ningú no espera una altra ronda de revisió per un nom de variable. Molts equips en diuen «aprovar confiant» (LGTM with nits).
Què fer amb els desacords
Els desacords tècnics són normals i sans. El que cal evitar és que s'enquistin al fil de la PR durant dies.
Protocol recomanat, per ordre:
- Aporta dades, no opinions. «Això és lent» no avança; «ho he mesurat amb mil tasques: 340 ms davant de 12 ms» avança.
- Distingeix l'important de l'estètic. Si no pots explicar quin problema real causa el que estàs criticant, probablement sigui una preferència. Marca-la com a
nit:i continua. - Si després de dues rondes continueu sense acord, surt del text. Una trucada de deu minuts resol el que vint comentaris no. Després, escriu la conclusió a la PR perquè quedi constància.
- Si continua sense resoldre's, escala amb un criteri acordat per endavant: la persona responsable d'aquella part del codi decideix, o un tercer desempata. L'important és que la regla existeixi abans del conflicte, no que s'improvisi durant.
- Documenta la decisió per no repetir la discussió d'aquí a tres mesos. Si és una convenció general, va al
CONTRIBUTING.md; si és una decisió d'arquitectura, a un document de decisió.
I una asimetria útil que molts equips adopten: qui proposa un canvi a l'statu quo té la càrrega de la prova. Si el projecte ja fa les coses d'una manera i el revisor en prefereix una altra, el revisor hauria de justificar el canvi, no l'autor defensar el que ja hi ha. Evita que cada PR es converteixi en un referèndum sobre l'estil del projecte.
Sobre els missatges de commit
Un tipus de comentari apareix a gairebé totes les revisions: el missatge del commit no explica el perquè, no segueix el format acordat, o diu «arreglos diversos». És un comentari legítim i val la pena fer-lo —l'historial és documentació permanent— però les regles concretes de redacció són el contingut de la lliçó 08-01. Allà veurem quin format fer servir, com estructurar el cos i com enllaçar els tiquets GT-NNN que els hooks del mòdul 6 ja validen.
Errors Habituals i Consells
Error 1: fer servir git diff main branca (o main..branca) per revisar. Barreja la feina de l'autor amb el que ha avançat main des que es va separar. Tres punts: git diff main...branca.
Error 2: confondre la semàntica dels punts entre diff i log. A diff vols ...; a log vols ... És contraintuïtiu i és així.
Error 3: revisar només al navegador. Sense executar el codi, la revisió detecta errades tipogràfiques i poca cosa més. Porta't la branca amb la referència de PR i prova-la.
Error 4: començar per l'estil. Es gasta tota l'atenció en el trivial i s'aprova un disseny equivocat. Correcció, disseny, llegibilitat, estil. En aquest ordre.
Error 5: comentar el que ja comprova el linter. És soroll, genera ressentiment i revela un buit a les eines del projecte, no al codi de l'autor.
Error 6: no distingir el bloquejant de l'opcional. L'autor es queda sense saber què ha de canviar per poder integrar. Fes servir prefixos explícits.
Error 7: rellegir la PR sencera després d'un rebase de l'autor. Per a això existeix git range-diff. Desa una branca amb el que vas revisar i compara.
Error 8: aprovar una PR de mil línies en cinc minuts. És pitjor que no revisar-la, perquè genera una falsa sensació de control. Demana que es trossegi.
Error 9: convertir la revisió en una demostració de superioritat tècnica. Destrueix la disposició de l'equip a proposar canvis, que és l'actiu que la revisió pretenia protegir.
Consell 1: git diff --stat main...branca sempre primer. Deu segons que orienten tota la revisió.
Consell 2: desa una branca marcadora després de revisar. git branch revisio/pr-42-v1 revisio/pr-42. El teu jo futur t'ho agrairà quan arribi la v2.
Consell 3: git range-diff @{u}...HEAD abans de cada push --force-with-lease. Verifica que el rebase no ha trencat res. Trenta segons ben invertits.
Consell 4: -U10 i --color-moved per defecte a les revisions. Més context i distinció entre codi mogut i reescrit.
Consell 5: un worktree dedicat a revisar. git worktree add ../revisio <branca>. Revisar deixa de costar canvi de context.
Consell 6: àlies per al que repeteixes. Per exemple git config --global alias.revisar '!f() { git fetch origin pull/$1/head:revisio/pr-$1 && git diff --stat main...revisio/pr-$1; }; f' (lliçó 06-04).
Exercicis
Exercici 1: dos punts i tres punts
- Crea un repositori amb
app.jsiestils.cssi tres commits amain. - Crea
funcionalitat/filtresdes d'allà i fes dos commits que només toquinapp.js. - Torna a
maini fes dos commits més que toquin nomésestils.css. - Executa
git diff main funcionalitat/filtres,git diff main..funcionalitat/filtresigit diff main...funcionalitat/filtres. Explica què mostra cadascun i per què el tercer és el correcte per revisar. - Demostra l'equivalència de la forma de tres punts fent servir
git merge-base. - Executa
git log --oneline main..funcionalitat/filtresigit log --oneline main...funcionalitat/filtres --left-right. Explica la diferència amb el cas dediff.
Exercici 2: revisar com l'Ana
Sobre el repositori anterior:
- Obtén el resum de fitxers i línies del canvi.
- Llista els commits de la branca amb els seus missatges complets.
- Recorre'ls un a un del més antic al més nou amb el seu diff.
- Mostra el diff complet amb deu línies de context i ignorant l'espaiat.
- Crea un worktree a
/tmp/revisioapuntant a la branca, sense abandonarmain. - Esbrina qui va escriure per última vegada les línies que la branca modifica, abans del canvi.
Exercici 3: range-diff en acció
- Desa una referència de la branca tal com està:
git branch revisio/v1 funcionalitat/filtres. - Simula la resposta de l'autor a una revisió: rebasa
funcionalitat/filtressobremain, modifica una línia d'un dels commits amb un rebase interactiu (edit) i afegeix un commit nou al final. - Executa
git range-diff main...revisio/v1 main...funcionalitat/filtres. - Identifica a la sortida quin commit és equivalent, quin ha canviat i quin és nou.
- Prova d'apujar
--creation-factori observa com canvia l'aparellament. - Genera els pedaços de la branca amb
git format-patch -v2 --cover-letteri aplica'ls en una branca nova ambgit am. Comprova que l'autor original es conserva.
Solucions
Solució 1:
mkdir /tmp/practica-revisio && cd /tmp/practica-revisio
git init -qb main
printf 'const tasques = [];\n' > app.js
printf 'body { margin: 0; }\n' > estils.css
git add . && git commit -q -m "Estructura inicial"
echo "function afegeix(t) { tasques.push(t); }" >> app.js
git commit -qam "Afegeix la funcio d'alta de tasques"
echo "function esborra(i) { tasques.splice(i, 1); }" >> app.js
git commit -qam "Afegeix la funcio d'esborrat"git switch -qc funcionalitat/filtres
echo "function filtra(f) { return tasques.filter(f); }" >> app.js
git commit -qam "Afegeix el filtratge de tasques"
echo "function comptaPendents() { return filtra(t => !t.feta).length; }" >> app.js
git commit -qam "Afegeix el comptador de pendents"git switch -q main
echo ".tasca { padding: 8px; }" >> estils.css
git commit -qam "Estila l'element de tasca"
echo ".tasca.feta { opacity: 0.5; }" >> estils.css
git commit -qam "Atenua les tasques completades"# 4. Les tres comparacions
git diff --stat main funcionalitat/filtres
git diff --stat main..funcionalitat/filtres
git diff --stat main...funcionalitat/filtresLes dues primeres formes són idèntiques i mostren estils.css amb línies eliminades que la branca no va tocar mai: són els commits de main vistos del revés. La tercera mostra només app.js, que és el que realment va fer la branca.
# 5. Equivalència
BASE=$(git merge-base main funcionalitat/filtres)
git diff --stat "$BASE" funcionalitat/filtres # idèntic al de tres punts< 4e8a1f7 Atenua les tasques completades < 2d6c9b3 Estila l'element de tasca > c9f1a2d Afegeix el comptador de pendents > 7b3e0c4 Afegeix el filtratge de tasques
A log, .. dóna els commits exclusius de la branca (el que vols) i ... dóna els dels dos costats. A diff és a l'inrevés. La causa és que diff compara arbres i log selecciona conjunts de commits.
Solució 2:
# 1, 2, 3
git diff --stat main...funcionalitat/filtres
git log --format='%h %s%n%n%b' main..funcionalitat/filtres
git log --reverse -p main..funcionalitat/filtresSolució 3:
# 1
git branch revisio/v1 funcionalitat/filtres
# 2. L'autor rebasa i corregeix
git switch -q funcionalitat/filtres
git rebase -q main
GIT_SEQUENCE_EDITOR="sed -i '1s/^pick/edit/'" git rebase -i main
sed -i 's/return tasques.filter(f);/return (tasques || []).filter(f);/' app.js
git commit -qam "Afegeix el filtratge de tasques" --amend
git rebase --continue
echo "function neteja() { tasques.length = 0; }" >> app.js
git commit -qam "Afegeix la neteja de la llista"1: 7b3e0c4 ! 1: a1f4d82 Afegeix el filtratge de tasques
@@ app.js
function esborra(i) { tasques.splice(i, 1); }
-function filtra(f) { return tasques.filter(f); }
+function filtra(f) { return (tasques || []).filter(f); }
2: c9f1a2d = 2: 5e2b7c9 Afegeix el comptador de pendents
3: -------- > 3: 8d3a6f1 Afegeix la neteja de la llista# 4. Lectura:
# commit 1 -> '!' : va canviar, i es veu exactament què (la guarda `|| []`)
# commit 2 -> '=' : equivalent, no cal rellegir-lo
# commit 3 -> '>' : nou, cal revisar-lo sencer# 6. Pedaços i aplicació
git format-patch -v2 --cover-letter -o /tmp/pedacos main..funcionalitat/filtres
ls /tmp/pedacos
git switch -qc revisio-pedacos main
git am /tmp/pedacos/v2-000[123]*.patch
git log --format='%h %an <%ae> %s' -3L'autor i la data originals es conserven: això és el que distingeix git am de git apply.
Conclusió
Revisar codi bé és una habilitat, i la meitat d'aquesta habilitat és tècnica. L'essencial:
- Una revisió serveix sobretot per difondre coneixement i mantenir la coherència; detectar defectes és important però és on menys aporta davant de les proves automàtiques. El que pot comprovar una màquina, que ho comprovi la màquina.
- El diff correcte per revisar és
git diff main...branca, amb tres punts: compara des de l'ancestre comú, no des de la punta demain, i per tant mostra només el que va fer l'autor. És el mateix que ensenyen les plataformes. - Compte amb l'asimetria: tres punts a
diff, dos punts alog.git log --oneline main..brancaper veure els commits proposats. - El repertori d'inspecció:
--statprimer sempre,-U10per a més context,-wper ignorar l'espaiat,--color-movedper distingir codi mogut de reescrit,--reverse -pper recórrer commit a commit, i un worktree per executar-lo de debò. git range-diffcompara dues versions de la mateixa sèrie de commits i marca cadascun com a igual (=), modificat (!), eliminat (<) o nou (>). Converteix una segona revisió després d'un rebase en cinc segons de feina. Fes-lo servir també sobre tu mateix abans de cadapush --force-with-lease.git request-pullgenera el correu que va donar nom a la «pull request», iformat-patch/amsón el model de revisió per correu del nucli de Linux, onrange-diffa la carta de presentació de la v2 és pràctica habitual.- Revisa per ordre: correcció → disseny → llegibilitat → estil, i no baixis de nivell sense tancar l'anterior.
- Comenta sobre el codi, no sobre la persona; marca explícitament el
bloquejant:davant delsuggeriment:i elnit:; i comenta també el que està bé. - La mida de la PR és el factor que més determina la qualitat de la revisió. Entre 50 i 200 línies és el punt òptim; per damunt de mil, la revisió és pràcticament fictícia. Trosseja, separa el mecànic del substancial, o revisa en parella.
- Aprovar vol dir «això millora el projecte», no «és perfecte». I tingues acordat per endavant com es desempaten els desacords.
L'equip ja sap proposar canvis i revisar-los. Però encara falta la peça de dalt: quines branques existeixen, per a què serveix cadascuna i cap a on van les propostes? En Diego obre la seva PR contra main… i si el projecte tingués una branca develop? I si calgués arreglar una errada urgent en una versió antiga que ja és en producció? Això són els fluxos de treball, i comencem pel més estructurat i clàssic de tots a la lliçó 07-03: Flux de Treball Git Flow.
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ó
