En tancar el mòdul 9 vam deixar l'Ana, el Bruno, la Carla i el Diego dominant Git sobre gestor-tasques: saben construir l'historial, reescriure'l amb criteri, col·laborar amb un procés i sortir dels embolics. Però gestor-tasques són quatre fitxers i quatre persones. El món real és més gran i més estrany.

Aquesta lliçó no ensenya ordres noves. Ensenya una cosa que a hores d'ara val més: criteri. Mirarem com fan servir Git quatre tipus de projecte molt diferents —des del més gran i més antic fins a un exactament igual que el vostre— i n'extraurem, de cadascun, quin problema resol el seu flux, quin preu paga per tenir-lo i què cal perquè funcioni.

La conclusió que busquem ja te l'avanço, perquè és l'única que cal endur-se'n: no existeix «el flux correcte de Git». Existeix el flux que encaixa amb la mida de l'equip, amb la confiança entre els seus membres, amb el ritme de publicació i amb el que costa equivocar-se. Copiar el flux del kernel de Linux en un equip de quatre persones és tan absurd com coordinar el kernel per pull requests d'una plataforma web.

Tot el que es descriu aquí és públic i ben documentat: els fluxos de treball del kernel són escrits a la seva pròpia documentació, els projectes de codi obert publiquen les seves guies de contribució, i les pràctiques de monorepo empresarial s'han descrit en articles i xerrades tècniques durant anys. Quan doni una magnitud, la donaré com a ordre de magnitud aproximat, mai com a dada exacta: el que importa és l'escala, no la xifra.

Contingut

  1. Com llegir un estudi de cas
  2. Cas 1: el kernel de Linux, el flux per correu electrònic
  3. La jerarquia de mantenidors i l'«arbre d'arbres»
  4. Per què el kernel no fa servir pull requests de plataforma
  5. Què exigeix el model del kernel a qui hi contribueix
  6. Cas 2: un projecte de codi obert de mida mitjana
  7. La infraestructura social d'un projecte obert
  8. Cas 3: una empresa amb monorepo
  9. Cas 4: un equip petit de producte (el nostre)
  10. Els quatre models, comparats
  11. La lliçó transversal: el flux es tria, no s'hereta

  1. Com llegir un estudi de cas

Abans de mirar cap projecte convé fixar les preguntes. Tot flux de treball amb Git, per complex que sembli, respon a cinc preguntes:

Pregunta Què determina
Com proposa un canvi algú de fora del nucli? El mecanisme de proposta: correu, pull request, branca directa
Qui decideix que un canvi hi entra? L'estructura d'autoritat: un mantenidor, dos revisors, un propietari de directori
Sobre quina branca es treballa i durant quant de temps? El model de branques i la seva vida mitjana
Quin aspecte té l'historial resultant? Si és lineal, si té fusions, si cada commit compila
Què cal perquè això funcioni? La infraestructura i la disciplina necessàries

La cinquena és la que gairebé sempre s'ignora, i la que explica per què un flux copiat d'un altre lloc fracassa. Un flux no és només una seqüència d'ordres: és una seqüència d'ordres més les eines, les normes i els hàbits que la sostenen.

Respondrem aquestes cinc preguntes per a cada cas.

  1. Cas 1: el kernel de Linux, el flux per correu electrònic

El kernel de Linux és el projecte per al qual es va escriure Git, el 2005, quan l'equip va perdre l'accés a l'eina que feia servir fins llavors. És també el projecte que continua fent servir el flux més antic i, per a gairebé tothom, el més sorprenent: els canvis es proposen per correu electrònic, en llistes públiques, en forma de pedaços de text.

Les magnituds, com a ordres de magnitud: desenes de milions de línies de codi, desenes de milers de fitxers, més de vint anys d'historial a Git (i més de trenta de projecte), i de l'ordre de milers de persones contribuint-hi cada any. Cap equip petit no s'assembla a això, i per això el cas és instructiu: mostra què passa quan portes la col·laboració amb Git al seu límit.

El cicle d'un pedaç

flowchart TD
    A["Desenvolupador<br/>fa commits locals"] --> B["git format-patch<br/>genera fitxers .patch"]
    B --> C["git send-email<br/>a la llista del subsistema"]
    C --> D["Revisió pública<br/>a la llista de correu"]
    D -->|"canvis demanats"| E["Nova versió: v2, v3…"]
    E --> C
    D -->|"acceptat"| F["Mantenidor:<br/>git am aplica el pedaç"]
    F --> G["Arbre del subsistema"]
    G --> H["git request-pull<br/>al mantenidor superior"]
    H --> I["Arbre principal (Linus)"]

Fixa't en un detall important: el pedaç viatja com a text, no com una referència a un repositori. Qui el rep no necessita afegir un remot, ni tenir accés al repositori de qui l'envia, ni tan sols saber si aquest repositori existeix. Rep un correu, i aquest correu conté el canvi sencer.

git format-patch: convertir commits en correus

# Genera un fitxer .patch per cada commit que tinc per sobre de main
git format-patch main
0001-net-corregeix-fuita-de-memoria-al-driver.patch
0002-net-afegeix-prova-de-regressio.patch

Cada fitxer és un correu complet: capçaleres, assumpte pres de la primera línia del missatge del commit, cos del missatge, i el diff al final. Si apliquem això al nostre projecte per veure-ho per dins:

git format-patch main --stdout | head -30
From 8a1f6c3d4e5b6a7c8d9e0f1a2b3c4d5e6f7a8b9c Mon Sep 17 00:00:00 2001
From: Ana Ferrer <[email protected]>
Date: Fri, 31 Jul 2026 13:11:58 +0200
Subject: [PATCH 1/2] GT-142 mostra el comptador de pendents

S'afegeix un comptador a la capçalera amb el nombre de tasques no
completades, que es recalcula en marcar o desmarcar una tasca.

Signed-off-by: Ana Ferrer <[email protected]>
---
 app.js     | 12 ++++++++++++
 index.html |  3 ++-
 2 files changed, 14 insertions(+), 1 deletion(-)

Aquest From 8a1f6c3d... de la primera línia no és una capçalera de correu real: és el hash del commit original, que Git hi desa perquè qui l'apliqui pugui saber d'on va sortir. La data Mon Sep 17 00:00:00 2001 és un valor sentinella històric que Git escriu sempre; no significa res.

Opcions que es fan servir de debò:

# Numerar i afegir una carta de presentació (0000-cover-letter.patch)
git format-patch main --cover-letter --numbered

# Marcar que és la segona versió de la sèrie després de la revisió
git format-patch main -v2

# Només els tres últims commits
git format-patch -3

# Amb el nom de la branca a l'assumpte, útil per a sèries llargues
git format-patch main --subject-prefix="PATCH gestor-tasques"

La carta de presentació (--cover-letter) és el correu 0/N de la sèrie: explica el conjunt, no cada pedaç. Al kernel és on s'argumenta el perquè del canvi complet, i on es resumeix què ha canviat respecte de la versió anterior de la sèrie.

git send-email: enviar-los

git send-email [email protected] \
               [email protected] \
               0001-*.patch 0002-*.patch

git send-email els envia com un fil de correu: la carta de presentació és el missatge arrel i els pedaços en pengen com a respostes. Cal configurar un servidor SMTP:

git config --global sendemail.smtpServer smtp.exemple.cat
git config --global sendemail.smtpUser [email protected]
git config --global sendemail.smtpEncryption tls
git config --global sendemail.smtpServerPort 587

És l'ordre que més gent ha instal·lat i mai no ha arribat a fer servir. Però convé conèixer-la: quan algú et digui «envia'm el pedaç», això és el que vol dir.

git am: aplicar el pedaç rebut

A l'altra banda, el mantenidor desa el correu i l'aplica:

# Aplicar una sèrie de pedaços en ordre
git am 0001-*.patch 0002-*.patch

# Aplicar directament des d'una bústia de correu
git am /ruta/a/la/bustia.mbox

# Afegir la meva pròpia signatura en aplicar-lo (pràctica estàndard al kernel)
git am --signoff 0001-*.patch

am vol dir apply mailbox. Crea un commit per pedaç conservant l'autor original i posant el mantenidor com a committer. Aquí es veu per primera vegada amb sentit pràctic la distinció autor/committer que va aparèixer al model de dades (lliçó 01-04): el kernel la fa servir constantment, perquè qui escriu el codi i qui l'integra gairebé mai no són la mateixa persona.

Si un pedaç no s'aplica netament:

# Veure on ha fallat
git am --show-current-patch=diff

# Intentar una aplicació amb més marge fent servir la informació de blobs
git am -3

# Arreglar a mà, marcar com a resolt i continuar
git add .
git am --continue

# O abandonar la sèrie sencera i tornar a l'estat previ
git am --abort

git am -3 (fusió a tres bandes) és el que salva la majoria dels casos: fa servir els hashos de blob que el pedaç porta incrustats per reconstruir el context i fer una fusió real en lloc d'una aplicació textual. És exactament el mecanisme de tres bandes de la lliçó 03-03, aplicat a un pedaç.

git request-pull: demanar que integrin el teu arbre

Quan el mantenidor d'un subsistema ja té els pedaços al seu repositori i vol que el nivell superior els integri, no envia pedaços: envia una petició d'extracció per correu, generada per Git:

git request-pull v6.10 https://git.exemple.cat/subsistema-xarxa.git per-a-6.11
The following changes since commit 3f2a1b9c...:

  Linux 6.10 (2026-06-14 18:02:11 -0700)

are available in the Git repository at:

  https://git.exemple.cat/subsistema-xarxa.git per-a-6.11

for you to fetch changes up to 9d4e7f2a...:

  net: afegeix prova de regressio (2026-07-28 11:40:03 +0200)

----------------------------------------------------------------
Ana Ferrer (2):
      net: corregeix fuita de memoria al driver
      net: afegeix prova de regressio

 drivers/net/exemple.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

Això és el pull request original, el de debò: un correu que diu «en aquest repositori, en aquesta branca, des d'aquest commit base, hi ha aquests canvis; emporta-te'ls». Les plataformes web que fem servir cada dia no van inventar el concepte: hi van posar una interfície a sobre. Tornarem sobre request-pull a la lliçó 10-02, com a pont entre els dos mons.

  1. La jerarquia de mantenidors i l'«arbre d'arbres»

El kernel no té un repositori: en té centenars. Cada subsistema —xarxa, sistemes de fitxers, gràfics, una arquitectura de processador concreta— té el seu propi repositori públic i el seu propi mantenidor.

flowchart BT
    D1["Col·laborador"] --> S1["Arbre d'un driver"]
    D2["Col·laborador"] --> S1
    D3["Col·laborador"] --> S2["Arbre d'un altre driver"]
    S1 --> M1["Arbre del subsistema<br/>(xarxa)"]
    S2 --> M1
    S3["Arbre del subsistema<br/>(sistemes de fitxers)"] --> T["Arbre principal"]
    M1 --> T
    S4["Arbre del subsistema<br/>(gràfics)"] --> T
    T --> R["Publicació<br/>vX.Y"]

El flux de la informació és de baix cap a dalt, per confiança. Cada nivell confia en el de sota perquè coneix aquestes persones i n'ha revisat la feina durant anys, i respon davant del de dalt pel que hi integra. L'arbre principal no revisa cada pedaç: revisa peticions d'extracció de mantenidors en qui confia.

Això té tres conseqüències tècniques molt visibles a l'historial:

  1. L'historial principal és ple de commits de fusió entre arbres de subsistema. No és desordre: cada fusió documenta «en aquesta data vaig integrar la feina d'aquest subsistema». El missatge d'aquestes fusions sol ser el text del request-pull corresponent.
  2. Els pedaços individuals arriben ja nets, perquè s'han discutit i reescrit a la llista abans d'entrar en cap arbre. La netedat no s'aconsegueix reescrivint després: s'aconsegueix no deixant entrar el que és brut.
  3. El ritme és de finestra. Hi ha períodes en què l'arbre principal accepta canvis nous i períodes en què només accepta correccions, tancant amb una publicació. Aquest ritme fa predictible la feina de tots els nivells inferiors.

Signed-off-by i el certificat d'origen

Cada commit del kernel porta una o diverses línies al final:

Signed-off-by: Ana Ferrer <[email protected]>
Signed-off-by: Bruno Salas <[email protected]>

No és una signatura criptogràfica (això és git commit -S, lliçó 08-05). És una declaració legal: qui la posa certifica que té dret a aportar aquest codi sota la llicència del projecte. S'anomena Developer Certificate of Origin, és un text públic i curt, i s'afegeix amb:

git commit --signoff -m "..."
git am --signoff pedac.patch

Cada nivell de la jerarquia hi afegeix la seva en integrar, de manera que el commit acaba portant la cadena completa de custòdia: qui el va escriure i per quines mans ha passat fins a l'arbre principal. És traçabilitat social escrita al mateix objecte commit.

  1. Per què el kernel no fa servir pull requests de plataforma

És la pregunta òbvia. La resposta no és «per costum» ni «per resistència al canvi», encara que la inèrcia hi pesi. Hi ha raons estructurals:

Raó Explicació
Independència de proveïdor Dependre d'una plataforma concreta significa que la seva política, la seva disponibilitat i el seu preu condicionen el projecte. El correu el serveix qualsevol.
La revisió és el producte En una llista, la discussió tècnica queda arxivada, és citable, es pot respondre en línia sobre el codi mateix i la llegeix gent que no seguia aquell canvi. És una revisió pública per defecte, no privada per defecte.
Escala de participants Milers de persones revisant en paral·lel centenars de sèries simultànies funciona millor amb filtres de correu que amb notificacions d'una interfície web.
Ningú no necessita permisos Per proposar un canvi no cal cap compte, ni cap fork, ni que ningú et doni accés a res. N'hi ha prou de saber l'adreça de la llista.
El pedaç és autocontingut Es pot aplicar, desar, reenviar, citar i arxivar sense dependre que cap servidor continuï existint d'aquí a quinze anys.

I també hi ha costos, que convé dir amb la mateixa claredat:

  • La barrera d'entrada és alta. Configurar el correu sortint perquè no destrossi els pedaços és un ritu de pas famós pel dolor que provoca.
  • No hi ha estat centralitzat de «en quin punt és aquesta proposta». Existeixen eines externes de seguiment de pedaços per pal·liar-ho, però no és el mateix que un plafó.
  • La integració contínua és més difícil de lligar a una proposta concreta, perquè la proposta és un correu, no una branca d'un servidor.

Els últims anys han aparegut eines que automatitzen les parts tedioses (enviar sèries, recuperar-les des dels arxius públics, gestionar versions successives) sense abandonar el correu. La tendència no és substituir el flux, sinó fer-lo menys aspre.

  1. Què exigeix el model del kernel a qui hi contribueix

Aquest és el punt de la lliçó on el cas deixa de ser una curiositat i comença a ser útil per a tu, encara que no enviïs mai cap pedaç al kernel.

Exigència 1: cada commit ha de ser correcte per si sol. No «el conjunt funciona»: cada commit compila i passa les proves, perquè git bisect (lliçó 06-02) ha de poder aturar-s'hi en qualsevol d'ells. Això obliga a partir la feina en passos coherents, i és el que converteix una sèrie de pedaços en una cosa revisable.

Exigència 2: el missatge es llegeix sol. Un mantenidor rep el pedaç en un correu, sense accés al teu tiquet, sense el teu context i sense poder preguntar-te al passadís. El missatge és la documentació del canvi. Tot el que vam veure a la lliçó 08-01 —el perquè abans que el què, l'imperatiu, el cos que explica l'alternativa descartada— aquí no és una bona pràctica: és un requisit de funcionament.

Exigència 3: una sèrie és una narració. Els pedaços s'ordenen de manera que cadascun prepari el següent: primer la refactorització que no canvia el comportament, després el canvi de comportament, després les proves. És exactament l'ús del rebase interactiu de la lliçó 05-02, amb un propòsit editorial.

Exigència 4: acceptes reescriure. La versió 5 d'una sèrie és normal. Es refà amb rebase -i, es torna a enviar amb -v5, i a la carta de presentació s'explica què ha canviat respecte de la v4. Per a això serveix git range-diff (lliçó 07-02), que compara dues versions d'una mateixa sèrie.

Aplicat al nostre projecte, així es prepararia l'Ana per enviar una sèrie en aquest estil:

# 1. Netejar la sèrie: reordenar, fusionar els «corregeix typo», reescriure missatges
git rebase -i main

# 2. Comprovar que cada commit compila, un per un
git rebase main --exec "npm test"

# 3. Generar la v2 i comparar-la amb la v1 que ja vaig enviar
git format-patch main -v2 --cover-letter
git range-diff main v1-final main

El --exec del segon pas és una joia poc coneguda: executa aquesta ordre després d'aplicar cada commit del rebase, i s'atura al primer que falli. És la manera mecànica de garantir l'exigència 1.

  1. Cas 2: un projecte de codi obert de mida mitjana

Baixem una escala. Parlem d'un projecte amb centenars de col·laboradors, desenes d'ells habituals, un grapat de mantenidors, i una plataforma d'allotjament (git.exemple.cat al nostre univers fictici). Una biblioteca popular, un marc de treball, una eina de línia d'ordres coneguda.

Aquest és exactament el model del Diego, el col·laborador extern de la lliçó 07-01, multiplicat per dos-cents.

El flux

flowchart LR
    A["Fork personal"] --> B["Branca de tema"]
    B --> C["Pull request<br/>al repositori principal"]
    C --> D["CI automàtica"]
    C --> E["Revisió humana"]
    D --> F{"Tot verd?"}
    E --> F
    F -->|sí| G["Condensat i fusió<br/>a main"]
    F -->|no| B

Res d'això no és nou per a tu: és el mòdul 7 sencer. El que canvia amb l'escala no és la mecànica, sinó quanta feina fa la infraestructura perquè els mantenidors no s'ofeguin.

L'aritmètica del mantenidor

La dada que explica tota la resta: en un projecte així, la revisió és el recurs escàs. Hi ha centenars de persones capaces d'escriure una proposta i potser cinc amb dret i temps per integrar-la. Cada minut que un mantenidor gasta explicant com s'executen les proves, demanant que es faci rebase d'una branca o tancant propostes duplicades és un minut que no dedica a revisar codi.

D'aquí que tot el disseny del procés persegueixi un objectiu: que la proposta arribi ja en condicions.

  1. La infraestructura social d'un projecte obert

Aquestes són les peces concretes, i mereixen atenció perquè són directament aplicables a qualsevol repositori, inclòs el vostre.

CONTRIBUTING.md

Un fitxer a l'arrel del repositori que les plataformes mostren automàticament a qui obrirà una proposta. Conté allò que un mantenidor està cansat de repetir:

# Com contribuir a gestor-tasques

## Abans de començar
- Obre una incidència abans d'escriure codi per a un canvi gran.
- Mira si ja existeix una proposta oberta sobre el mateix.

## Preparar l'entorn
    git clone https://git.exemple.cat/gestor-tasques.git
    npm install
    npm test

## Convencions
- Missatges de commit: Conventional Commits (feat:, fix:, docs:…).
- Una proposta, un tema. Si la teva branca toca dues coses, parteix-la en dues.
- Fes rebase sobre `main` abans de demanar revisió; no fusionis `main` a la teva branca.

## Què has d'esperar
- La CI ha d'estar en verd abans que la revisem.
- Un mantenidor respondrà en uns dies laborables.
- Integrem amb condensat: la teva branca es converteix en un commit a `main`.

Fixa't en l'última línia. Dir per endavant quina política d'integració s'aplica (fusió, condensat o rebase, lliçó 08-02) evita la discussió més recurrent a les propostes de gent nova.

Plantilles de proposta i d'incidència

Fitxers dins d'un directori de configuració de la plataforma que precarreguen el formulari. La plantilla de proposta sol ser una llista de comprovació:

## Què canvia

<!-- Descripció breu del canvi i del problema que resol -->

## Tiquet relacionat

Tanca GT-

## Comprovacions

- [ ] He executat `npm test` en local i passa
- [ ] He afegit proves per al comportament nou
- [ ] He actualitzat el README si el canvi afecta l'ús
- [ ] Els meus commits segueixen Conventional Commits

El seu efecte real no és documental, és psicològic: qui obre la proposta veu les caselles buides i se li acut revisar-les abans que li ho demanin.

Etiquetes

Un sistema d'etiquetes ben pensat converteix una llista inabastable d'incidències en un mapa navegable:

Família d'etiquetes Exemples Per a què serveix
Tipus error, millora, documentació Classificar d'un cop d'ull
Estat necessita-revisió, esperant-resposta, bloquejat Saber de qui és el torn
Dificultat primera-contribució, ajuda-buscada Canalitzar la gent nova
Àrea interfície, emmagatzematge, ci Encaminar cap al mantenidor adequat

L'etiqueta primera-contribució (o el seu equivalent habitual en anglès) és la més rendible de totes: és com un projecte converteix lectors en col·laboradors.

Automatització d'allò repetitiu

En un projecte d'aquesta escala, els robots fan la feina que a gestor-tasques fa una persona:

name: Comprovacions de proposta

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  validar:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Comprovar el format dels missatges de commit
        run: |
          git log --format=%s origin/main..HEAD | while read -r assumpte; do
            echo "$assumpte" | grep -qE '^(feat|fix|docs|refactor|test|chore)(\(.+\))?: .+' \
              || { echo "Missatge no conforme: $assumpte"; exit 1; }
          done

      - name: Verificar que la branca està al dia amb main
        run: |
          git merge-base --is-ancestor origin/main HEAD \
            || echo "::warning::Fes rebase sobre main abans de demanar revisió"

      - name: Proves
        run: npm ci && npm test

Aquest git merge-base --is-ancestor és una ordre de lampisteria (lliçó 09-06) que respon amb un codi de sortida: és origin/main un avantpassat de HEAD? Si ho és, la branca està al dia.

Quin historial produeix aquest model

Gairebé sempre lineal a main, amb un commit per proposta integrada, missatge normalitzat i una referència al número de la proposta. És el resultat de la política de condensat, i té una virtut enorme a aquesta escala: git log --oneline a main es llegeix com un registre de canvis del projecte, no com el diari de dues-centes persones.

El preu, ja discutit a la lliçó 08-02, és que es perd el detall intern de cada proposta. En un projecte obert s'accepta de bon grat, perquè aquest detall continua existint a la proposta mateixa, arxivada a la plataforma.

  1. Cas 3: una empresa amb monorepo

Tercer model, radicalment diferent: una sola empresa, un sol repositori, molts productes a dins. L'aplicació web, el servei de dades, l'aplicació mòbil, les biblioteques compartides, les definicions d'infraestructura: tot al mateix arbre de directoris i al mateix historial.

Diverses empreses grans han descrit públicament aquest model durant anys. Les magnituds, sempre com a ordre de magnitud: centenars de milers a milions de fitxers, milions de commits, i milers de persones treballant sobre el mateix repositori. A aquesta escala, Git de sèrie no n'hi ha prou, i aquest és el tema de la lliçó 10-04. Aquí ens interessa el perquè, no el com.

Per què algú tria això

Raó 1: el canvi atòmic entre projectes. Si la biblioteca compartida canvia d'interfície i hi ha trenta consumidors, en un monorepo això és un sol commit que actualitza la biblioteca i els trenta alhora. Mai no existeix un instant en què el repositori sigui incoherent. Amb repositoris separats, aquest mateix canvi són trenta-una propostes coordinades, versions intermèdies de compatibilitat i setmanes de feina.

Aquest és exactament el problema que vam deixar obert a la lliçó 06-05 amb components-ui: quan canvia el submòdul, cal actualitzar el punter al repositori pare, i durant una estona les dues coses no quadren. En un monorepo aquest problema no existeix perquè no hi ha dos repositoris.

Raó 2: la refactorització global és possible. Reanomenar una funció usada a tota l'empresa és una cerca i substitució més un commit. Amb repositoris separats, és un projecte.

Raó 3: una sola versió de tot. No hi ha «quina versió de la biblioteca fa servir el servei de facturació». Fa servir la que és a main, igual que tothom.

Raó 4: visibilitat i reutilització. Qualsevol pot llegir qualsevol codi, trobar qui el manté i proposar-hi un canvi.

El preu

Cost Com es paga
Git de sèrie s'ofega Clons parcials, sparse-checkout, servidors especialitzats, memòries cau de compilació (10-04)
Tothom ho veu tot Pot ser inacceptable si hi ha codi amb requisits de confidencialitat
La CI no ho pot executar tot Cal CI selectiva: calcular què queda afectat pel canvi
Eines pròpies Sistema de compilació amb graf de dependències, eines de propietat de codi, automatització de migracions
Ningú no pot clonar i començar La incorporació de gent nova requereix formació en l'entorn

Propietat del codi per directoris

La peça organitzativa clau. Un fitxer de text al repositori declara qui ha d'aprovar els canvis de cada zona de l'arbre:

# CODEOWNERS
# Regla per defecte: l'equip de plataforma
*                           @plataforma

# Cada equip és amo del seu directori
/serveis/facturacio/        @equip-facturacio
/serveis/tasques/           @equip-tasques
/biblioteques/components-ui/ @equip-disseny @equip-tasques

# El que és crític exigeix aprovació addicional
/infra/produccio/           @plataforma @seguretat
/biblioteques/autenticacio/ @seguretat

La plataforma llegeix aquest fitxer, calcula quins directoris toca cada proposta i assigna automàticament els revisors obligatoris. Combinat amb les branques protegides de la lliçó 07-06, el resultat és que l'autonomia es recupera sense renunciar al repositori únic: cada equip mana en el que és seu, però tocar la biblioteca d'autenticació requereix el vistiplau de seguretat.

És la resposta a l'objecció més freqüent contra el monorepo. «Si està tot junt, qualsevol pot canviar qualsevol cosa?» Tècnicament sí; a la pràctica, no sense l'aprovació de qui és amo d'aquella zona.

Integració contínua selectiva

Si el repositori té mil projectes, executar les proves dels mil a cada proposta és impossible. La solució és calcular el conjunt afectat:

name: CI selectiva

on: [pull_request]

jobs:
  detectar:
    runs-on: ubuntu-latest
    outputs:
      afectats: ${{ steps.calc.outputs.llista }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - id: calc
        name: Quins projectes toca aquesta proposta
        run: |
          # Fitxers modificats respecte del punt de divergència amb main
          CANVIS=$(git diff --name-only origin/main...HEAD)
          # Primer nivell de directori = projecte
          PROJECTES=$(echo "$CANVIS" | cut -d/ -f1-2 | sort -u | tr '\n' ' ')
          echo "llista=$PROJECTES" >> "$GITHUB_OUTPUT"

  provar:
    needs: detectar
    if: needs.detectar.outputs.afectats != ''
    runs-on: ubuntu-latest
    steps:
      - run: echo "Provant només ${{ needs.detectar.outputs.afectats }}"

Aquest origin/main...HEAD amb tres punts és el mateix de la revisió de codi de la lliçó 07-02: els canvis de la branca des que se'n va separar, no les diferències amb l'estat actual de main. És un detall que aquí importa molt: amb dos punts, qualsevol avanç de main faria creure a la canonada que la proposta toca projectes que no ha tocat.

A la pràctica, un sistema seriós no fa servir directoris sinó el graf de dependències del sistema de compilació: si canvia components-ui, també es proven tots els projectes que en depenen. Però el principi és el mateix, i arrenca sempre en un git diff --name-only.

  1. Cas 4: un equip petit de producte (el nostre)

Quart cas: quatre persones, un producte, una publicació cada poques setmanes. És a dir, gestor-tasques. És també, de bon tros, el cas més comú: la immensa majoria dels equips del món s'assemblen molt més a aquest que als tres anteriors.

Recapitulant el que aquest equip ha anat construint al llarg del curs, sense repetir-ne el detall:

  • Un repositori a git.exemple.cat, més components-ui com a submòdul (06-05).
  • Branques de tema curtes amb nom de tiquet (GT-231-filtre-ocultes), integrades a main mitjançant proposta i revisió (07-01, 07-02), amb un flux proper a GitHub Flow (07-04).
  • Integració contínua a cada proposta i branca protegida a main (07-06).
  • Conventional Commits i una política d'integració acordada (08-01, 08-02).
  • Etiquetes anotades amb SemVer per publicar (05-05).
  • El Diego, col·laborador extern, treballa per fork i proposta (07-01).

L'interessant d'aquest cas és el que NO té, i no necessita:

No té Per què no li cal
Jerarquia de mantenidors Quatre persones es parlen entre elles; la jerarquia seria teatre
Flux per correu Tots tenen accés d'escriptura al mateix servidor
CODEOWNERS Qualsevol pot revisar qualsevol fitxer, i és sa que sigui així
CI selectiva Les proves del projecte sencer triguen dos minuts
Clons parcials o sparse-checkout El repositori pesa menys que una fotografia
Git LFS No hi ha binaris grans… encara (10-03)
Branques de publicació de llarga vida Només hi ha una versió en producció alhora

Cadascuna d'aquestes absències és una decisió de disseny, no una mancança. Afegir-ne qualsevol «perquè els projectes seriosos ho fan» empitjoraria el flux: més passos, més cerimònia, més llocs on equivocar-se, i zero problemes resolts.

Aquest és el biaix professional més car que existeix en aquesta matèria: confondre la complexitat del procés amb la maduresa de l'equip.

  1. Els quatre models, comparats

Kernel de Linux Projecte obert mitjà Monorepo d'empresa Equip de producte
Mida Milers de persones, centenars de subsistemes Centenars de col·laboradors, pocs mantenidors Centenars o milers de persones, un repositori 3–15 persones
Mecanisme de proposta Pedaç per correu (format-patch/send-email/am) Fork + pull request en plataforma Branca al repositori central + proposta Branca al repositori central + proposta
Qui decideix Jerarquia de mantenidors per confiança Mantenidors del projecte Propietaris del directori (CODEOWNERS) Qualsevol company de l'equip
Flux de branques Arbres independents que es fusionen cap amunt; finestres d'integració Branques de tema curtes sobre main Branques de tema molt curtes; main sempre desplegable Branques de tema curtes sobre main
Historial resultant Moltes fusions entre arbres; cada commit vàlid per si sol Lineal, un commit per proposta (condensat) Lineal i d'altíssim volum Lineal o gairebé, llegible a ull nu
Reescriptura Constant i esperada (v2, v3…) abans d'integrar Freqüent abans d'integrar Poca: s'integra ràpid i petit Ocasional, per netejar la branca
Publicació Finestres i cicle de candidates Etiquetes SemVer Contínua, sense versió global Etiquetes SemVer
Què cal Disciplina extrema en commits i missatges; cultura de revisió pública; tolerància a la reescriptura CONTRIBUTING.md, plantilles, etiquetes, CI fiable, mantenidors amb temps Eines pròpies, CI selectiva, escalat de Git, propietat del codi Confiança mútua, CI bàsica, convencions acordades
Falla quan Algú envia un pedaç sense context o sense partir Els mantenidors se saturen o la CI és lenta i inestable Les eines no segueixen el ritme del repositori S'afegeix cerimònia que ningú no necessita

Llegeix-la en vertical, no en horitzontal: cada columna és un sistema coherent, on cada casella sosté les altres. La disciplina extrema del kernel és possible perquè hi ha una jerarquia de confiança que l'exigeix; la jerarquia és sostenible perquè els pedaços arriben impecables. Treure una casella de la seva columna i ficar-la en una altra sol produir un desastre.

  1. La lliçó transversal: el flux es tria, no s'hereta

Si hagués de reduir aquesta lliçó a una frase seria aquesta: el flux de treball és una resposta a unes restriccions concretes. Canvia les restriccions i la resposta correcta canvia.

Les restriccions que de debò importen són quatre:

1. Quanta confiança hi ha entre qui hi contribueix? Amb confiança alta (un equip intern), l'accés d'escriptura directe i la revisió lleugera funcionen. Amb confiança baixa o desconeguda (qualsevol d'internet), cal un mecanisme on la proposta arribi sense permisos i l'aprovació sigui explícita: fork i proposta, o pedaç per correu.

2. Quant costa un error en producció? Si tornar a desplegar costa trenta segons, et pots permetre integrar ràpid i corregir després (07-05). Si l'error implica retirar microprogramari de dispositius, necessites finestres, candidates i branques d'estabilització (07-03).

3. Quantes versions tens vives alhora? Una sola versió en producció permet un main únic. Mantenir tres versions simultànies amb correccions de seguretat obliga a branques de llarga vida i a cherry-pick sistemàtic (05-03).

4. Quant pesa el repositori i quanta gent el toca? És el que decideix si necessites les tècniques de la lliçó 10-04 o si Git de sèrie et sobra durant els pròxims deu anys.

L'antipatró

L'error clàssic té un guió sempre igual:

Algú llegeix un article sobre com treballa una empresa enorme. Proposa adoptar-ho. S'instal·len cinc eines, es defineixen set tipus de branca i una política d'aprovació de tres nivells. Dos mesos després, en un equip de cinc persones, integrar un canvi de dues línies triga tres dies i ningú no recorda per què.

El procés d'una organització de cinc mil persones és la cicatriu de problemes que aquella organització va tenir. Si no tens aquests problemes, el que estàs copiant no és una solució: és una cicatriu aliena.

La recepta sana

  1. Comença amb el flux més simple que funcioni. Per a gairebé tothom: branques de tema curtes, propostes amb revisió, main protegit, CI que passa en minuts.
  2. Afegeix procés només quan faci mal alguna cosa concreta. I que la conversa comenci pel dolor, no per l'eina: «se'ns va trencar producció tres vegades aquest mes» és un motiu; «hauríem de fer servir Git Flow» no ho és.
  3. Escriu les decisions. Al CONTRIBUTING.md o al README.md. Un flux que només viu al cap de dues persones no sobreviu a la tercera contractació.
  4. Revisa'l de tant en tant. Un procés adequat per a quatre persones pot ser insuficient per a dotze i absurd quan tornin a ser quatre.

Errors Habituals i Consells

Error 1: copiar el flux d'un projecte que no s'assembla al teu. És l'error central d'aquesta lliçó. Abans d'adoptar res, pregunta't quin problema resolia en el seu context original i si tu el tens.

Error 2: creure que format-patch/am és cosa de museu. És la manera més portable que existeix de moure un canvi entre dos repositoris sense connectar-los. Serveix per enviar una correcció a un company sense xarxa compartida, per moure un commit entre dos repositoris que no es coneixen, o per arxivar un canvi com a text. Ho reprenem a la lliçó 10-02.

Error 3: confondre git request-pull amb el pull request d'una plataforma. El primer genera un text que tu envies pel mitjà que vulguis; el segon és un objecte gestionat per un servidor, amb estat, comentaris i comprovacions. Conceptualment són el mateix; operativament, no.

Error 4: pensar que el monorepo és «tot junt sense ordre». Un monorepo que funciona té més estructura que un conjunt de repositoris separats: propietat per directoris, graf de dependències explícit i CI selectiva. El que elimina no és l'ordre, sinó la coordinació entre repositoris.

Error 5: fer servir el prestigi d'un projecte com a argument tècnic. «El kernel ho fa així» no és una raó. La raó és per què ho fa així, i si això s'aplica al teu cas.

Consell 1: aprèn a llegir l'historial d'un projecte aliè. És la manera més ràpida d'entendre com treballa un equip abans de contribuir-hi:

git clone --filter=blob:none https://git.exemple.cat/projecte.git
cd projecte

# Hi ha fusions o l'historial és lineal?
git log --oneline --graph -40

# Quina proporció de commits són fusions?
git rev-list --count --merges HEAD
git rev-list --count HEAD

# Quina convenció de missatges fan servir?
git log --format=%s -40

# Qui integra de debò? (committer, no autor)
git log --format='%cn' -300 | sort | uniq -c | sort -rn | head

# Fan servir Signed-off-by?
git log --format=%b -60 | grep -c 'Signed-off-by'

Aquest --filter=blob:none del clon és un clon parcial: porta el graf complet però no el contingut dels fitxers. Per inspeccionar un historial és perfecte i moltíssim més ràpid. S'explica a la lliçó 10-04.

Consell 2: abans de contribuir a un projecte, llegeix-ne el CONTRIBUTING.md sencer. Sona obvi i gairebé ningú no ho fa. És la diferència entre una proposta que s'integra i una que es queda sis mesos esperant.

Consell 3: si el teu equip no té el flux escrit, escriu-l'hi tu. Mitja pàgina al README.md: quines branques hi ha, com s'anomenen, com s'integra, com es publica. És l'aportació amb millor relació esforç/benefici que pots fer.

Exercicis

Exercici 1: moure un canvi sense remot compartit

L'Ana i el Bruno són en un tren sense connexió, compartint una xarxa local. L'Ana té tres commits a la branca GT-244-ordre-per-prioritat que el Bruno necessita al seu repositori. No hi ha cap servidor accessible.

Descriu dues maneres d'aconseguir-ho amb el que has après al curs, i explica quan preferiries cadascuna.

Exercici 2: diagnosticar un flux pel seu historial

Has clonat un projecte desconegut i n'obtens aquestes dades:

$ git rev-list --count HEAD
18452

$ git rev-list --count --merges HEAD
6127

$ git log --format=%s -8
Merge tag 'xarxa-per-a-6.11' de git.exemple.cat/subsistema-xarxa
Merge tag 'fitxers-per-a-6.11' de git.exemple.cat/subsistema-fitxers
net: corregeix fuita de memoria al driver
net: afegeix prova de regressio
Merge tag 'grafics-per-a-6.11' de git.exemple.cat/subsistema-grafics
docs: actualitza la guia de contribucio
Merge tag 'usb-per-a-6.11' de git.exemple.cat/subsistema-usb
Merge tag 'audio-per-a-6.11' de git.exemple.cat/subsistema-audio

$ git log --format='%an|%cn' -6
Ana Ferrer|Bruno Salas
Carla Vidal|Bruno Salas
Diego Rueda|Ana Ferrer
Ana Ferrer|Bruno Salas

A quin dels quatre models correspon? Justifica-ho amb tres indicis diferents.

Exercici 3: triar flux per a tres equips

Per a cada situació, decideix el model de treball i justifica'l en tres o quatre línies. Digues també què no hi afegiries.

A. Cinc persones, aplicació web interna, desplegament diverses vegades al dia, tots a la mateixa oficina, el repositori pesa 40 MB.

B. Una biblioteca de codi obert amb vint col·laboradors habituals i uns dos-cents ocasionals a l'any. Dos mantenidors amb poc temps. Es fa servir en producció en molts llocs, així que una versió trencada és un problema seriós.

C. Empresa de 400 persones, dotze productes que comparteixen quatre biblioteques internes. Avui tenen setze repositoris i es passen la vida coordinant versions entre ells. Cada canvi d'una biblioteca compartida triga setmanes a arribar a tots els consumidors.

Solucions

Solució 1

Manera A: git bundle (lliçó 09-05).

# Ana: empaqueta els tres commits en un fitxer
git bundle create /tmp/GT-244.bundle main..GT-244-ordre-per-prioritat

# (copia el fitxer a la màquina del Bruno per la xarxa local o un USB)

# Bruno: comprova què necessita el paquet i què conté
git bundle verify /tmp/GT-244.bundle
git bundle list-heads /tmp/GT-244.bundle

# Bruno: se'l porta com si fos un remot
git fetch /tmp/GT-244.bundle GT-244-ordre-per-prioritat:GT-244-ordre-per-prioritat

Manera B: format-patch + am (aquesta lliçó).

# Ana
git format-patch main -o /tmp/pedacos-gt244/

# Bruno
git checkout -b GT-244-ordre-per-prioritat main
git am /tmp/pedacos-gt244/*.patch

Quan cadascuna:

bundle format-patch/am
Què transporta Objectes Git reals, amb els seus hashos El contingut dels canvis, com a text
Hashos resultants Idèntics als de l'Ana Diferents: canvia el committer i la data
Llegible a ull nu No, és binari Sí, és text revisable
Aplicable sobre una altra base No: exigeix tenir el commit base Sí, i amb -3 fins i tot amb divergències
Volum Eficient per a molts commits Un fitxer per commit

Tria bundle quan vulguis la història exacta (mateixos hashos, mateixa signatura, mateixos pares). Tria format-patch quan vulguis el canvi per revisar-lo, discutir-lo o aplicar-lo sobre una base diferent. I hi ha una tercera via si les dues màquines es veuen a la xarxa: afegir el repositori del company com a remot per ruta de sistema de fitxers o per SSH i fer un fetch normal (lliçó 04-02) —Git és distribuït, i qualsevol clon pot ser el remot d'un altre.

Solució 2

És el cas 1: el model del kernel, o qualsevol projecte organitzat com a arbre d'arbres. Tres indicis independents:

  1. La proporció de fusions és del 33 % (6.127 de 18.452). Un historial amb un terç de commits de fusió no surt d'un flux de branques de tema amb condensat, que produeix un historial gairebé lineal. Surt d'un model on s'integren repetidament arbres complets.

  2. Els missatges de fusió diuen Merge tag '...-per-a-6.11' de git.exemple.cat/subsistema-.... Estan integrant etiquetes de repositoris diferents, cadascun d'un subsistema, tots preparats per a la mateixa versió. És literalment el resultat d'una sèrie de git request-pull seguits d'un git merge d'arbres independents.

  3. Autor i committer difereixen sistemàticament, i els committers són un conjunt petit i repetit (Bruno, Ana) mentre que els autors són variats (Carla, Diego). Això és l'empremta dactilar de git am: hi ha persones que escriuen pedaços i persones diferents que els apliquen. En un flux de pull requests de plataforma amb condensat, el committer sol ser el servidor mateix o el mateix autor.

Un quart indici de reforç: els missatges dels commits normals porten prefix de subsistema (net:, docs:), la convenció habitual quan l'arbre s'organitza per àrees.

Solució 3

A. Equip petit de producte (cas 4).

Branques de tema curtes sobre main, proposta amb una revisió, CI que executi les proves, main protegit, integració amb condensat o rebase, desplegament des de main. És GitHub Flow (07-04) o fins i tot Trunk Based (07-05) si tenen bona cobertura de proves i fan servir banderes de funcionalitat.

No hi afegiria: Git Flow amb develop i branques de publicació (no hi ha múltiples versions vives), CODEOWNERS (cinc persones que seuen juntes), CI selectiva, ni cap tècnica d'escalat. 40 MB no és un problema de rendiment: és un repositori petit.

B. Projecte obert mitjà (cas 2).

Fork i proposta, CONTRIBUTING.md explícit, plantilles de proposta i d'incidència, etiquetes per al triatge i per captar gent nova, CI obligatòria i ràpida, integració amb condensat, publicacions amb etiqueta anotada i SemVer.

Com que «una versió trencada és un problema seriós», hi afegiria una branca de manteniment per versió major viva (1.x, 2.x) on es porten les correccions amb cherry-pick (05-03), i publicaria candidates abans d'una versió major. Aquest és l'únic punt on prenc prestada una peça de Git Flow, i per un motiu concret.

No hi afegiria: un flux per correu (la barrera d'entrada enfonsaria les contribucions ocasionals, que aquí són valuoses), ni develop (amb main estable i branques de manteniment n'hi ha prou), ni jerarquia de mantenidors (amb dues persones no hi ha jerarquia que valgui).

C. Candidat clar a monorepo (cas 3).

El símptoma que descriuen —setmanes per propagar un canvi d'una biblioteca compartida a dotze consumidors— és exactament el problema que el monorepo elimina d'arrel: un commit atòmic actualitza la biblioteca i tots els seus consumidors alhora.

Abans de decidir, comprovaria tres coses:

  • Que no hi ha codi amb requisits de confidencialitat que impedeixin la visibilitat total.
  • Que estan disposats a invertir en eines: CI selectiva i un sistema de compilació amb graf de dependències. Sense això, el monorepo es converteix en una canonada de dues hores per canvi.
  • Que el volum resultant és manejable, o que accepten les tècniques de la lliçó 10-04.

Com a pas intermedi i reversible, començaria fusionant només les quatre biblioteques compartides en un repositori únic amb CODEOWNERS per directori, mesurant-ne l'efecte, i consolidant els productes després si l'experiència és bona.

No hi afegiria d'entrada: submòduls (06-05) per lligar les biblioteques als productes. Resoldrien la traçabilitat però no el problema real, que és la coordinació: continuarien necessitant dotze actualitzacions de punter, una per producte.

Conclusió

Quatre projectes, quatre respostes diferents a les mateixes cinc preguntes.

  • El kernel de Linux treballa amb pedaços per correu: git format-patch converteix commits en correus, git send-email els envia a llistes públiques, git am els aplica conservant l'autor original, i git request-pull demana a un nivell superior que integri un arbre sencer. Sobre això s'aixeca una jerarquia de mantenidors basada en la confiança, amb Signed-off-by: com a cadena de custòdia. El preu d'admissió és alt: cada commit ha de valer per si sol i cada missatge s'ha de poder llegir sense context.
  • Un projecte obert mitjà fa servir fork i proposta, i dedica tot el seu disseny a protegir el recurs escàs, que és el temps dels mantenidors: CONTRIBUTING.md, plantilles, etiquetes i automatització d'allò repetitiu. L'historial resultant és lineal i llegible.
  • Una empresa amb monorepo tria el repositori únic pel canvi atòmic entre projectes i la refactorització global, i paga aquest benefici amb eines pròpies, propietat del codi per directoris i CI selectiva calculada a partir de git diff --name-only origin/main...HEAD.
  • Un equip petit de producte —el nostre— funciona amb branques curtes, propostes i main protegit, i la seva virtut més gran és tot el que no té.

I la lliçó transversal, que és l'única que cal memoritzar:

El flux de treball es tria a partir de quatre restriccions —confiança entre qui hi contribueix, cost d'un error en producció, nombre de versions vives i mida del repositori— i no a partir del prestigi de qui el fa servir.

El procés d'una organització enorme és la cicatriu dels problemes que aquella organització va tenir. Si no tens aquests problemes, copiar-lo és adoptar-ne el cost sense el benefici.

El que ve

En els quatre casos ha aparegut alguna cosa que no és Git: llistes de correu, plataformes de propostes, sistemes de compilació, eines de seguiment de pedaços, canonades d'integració. Git gairebé mai no es fa servir sol. Viu envoltat d'editors que mostren diferències en color, de clients gràfics, de sistemes de tiquets que volen saber quin commit va tancar la incidència GT-231, de linters que s'executen abans de cada confirmació i de plataformes que converteixen un historial en una conversa.

Aquesta capa d'integració canvia per complet l'experiència diària i, mal entesa, és també on més gent perd el control del que està fent: el botó «Sincronitza» d'un editor amaga com a mínim dues ordres, i no sempre les que un espera.

A la lliçó 10-02: Integrant Git amb Altres Eines veurem què aporta de debò cada peça de l'ecosistema, què convé continuar fent al terminal i per què el consell de fons és sempre el mateix: automatitza allò repetitiu, però entén sempre quina ordre hi ha a sota.

Dominant Git: De Principiant a Avançat

Mòdul 1: Introducció a Git

Mòdul 2: Operacions Bàsiques de Git

Mòdul 3: Branques i Fusió

Mòdul 4: Treballant amb Repositoris Remots

Mòdul 5: Operacions Avançades de Git

Mòdul 6: Eines i Tècniques de Git

Mòdul 7: Estratègies de Col·laboració i Flux de Treball

Mòdul 8: Bones Pràctiques i Consells de Git

Mòdul 9: Resolució de Problemes i Depuració

Mòdul 10: Git al Món Real

© Copyright 2026. Tots els drets reservats