Git en equip
- Estratègies de branques
- Pull requests i merge requests
- Commits fàcils de revisar
- Integrar la branca a main
- Fluxos de treball de la indústria
- CI/CD
- Pràctiques actuals amb PR
- Per començar
- Referències
A Workflow Git hem vist com dues persones comparteixen un repositori fent commit directament a main. Per començar és l’enfocament més senzill, però quan hi ha tests i desplegaments automàtics, o quan l’equip creix, cal organitzar-se millor.
Aquest document respon a la pregunta que ve després: com porta un equip els seus canvis a main sense trencar-lo? Farem servir un exemple al llarg de tot el text: un equip de tres persones que desenvolupa una botiga en línia, on a tu et toca afegir la cerca de productes.
El recorregut va de menys a més. Primer, les peces: branques, pull requests, commits fàcils de revisar i com integrar la branca a main. Després, com la indústria combina aquestes peces en fluxos amb nom propi (GitHub flow, trunk-based development, Git flow) i com s’hi connecten els sistemes de CI/CD. Acabarem amb les pràctiques més recents al voltant de la revisió de codi i un punt de partida per al teu propi projecte.
Estratègies de branques
Si puges a main la cerca a mitges i no compila, bloqueges els teus companys. Si la guardes tres setmanes sense compartir-la, el codi de tothom haurà canviat tant que integrar-la serà un malson. Qualsevol estratègia de branques busca l’equilibri entre dues necessitats que tiren en sentits contraris:
- Aïllar la feina a mitges, perquè no molesti ningú.
- Integrar sovint, perquè les diferències entre la feina de cadascú no s’acumulin.
Les branques són l’eina per decidir on viu cada canvi mentre no està llest: a la vista de tothom o apartat. I són una eina molt lleugera, perquè una branca és només un punter mòbil a un commit, no una còpia dels teus arxius. Crear-la és instantani i pràcticament gratis (git només desa un nom que apunta a un commit), i canviar de branca és moure el HEAD d’un punter a un altre. Quan fas un commit, la branca on ets simplement avança per apuntar al commit nou. No dupliques res, només poses etiquetes a punts de la història.
Hi ha dues opcions bàsiques, una a cada extrem: prescindir de branques i integrar-ho tot a main al moment, o aïllar cada tasca en la seva pròpia branca.
Commit directe a main
Cada membre fa commits i pushes directament a main. La integració és contínua i el feedback immediat. És l’estratègia més senzilla, la que vam fer servir a Workflow Git, però no sempre és la millor.
# Al principi de la sessió: sincronitzar
git pull origin main
# Treballar, fer commits
git add arxius_modificats
git commit -m "descripció del canvi"
git push origin main
El problema és que no hi ha cap filtre: un error que arriba a main afecta immediatament tot l’equip. Només és assumible en projectes sense tests ni desplegaments automàtics (CI/CD), que veurem més endavant.
Feature branches (branques per tasca)
Cada unitat de treball viu en una feature branch, una branca de curta durada amb el nom de la tasca. Per a la cerca de productes, feature/cerca. La branca es fusiona a main quan la tasca és completa i provada.
# Crear una branca per la tasca
git switch -c feature/cerca
# Treballar i fer commits
git add arxius_modificats
git commit -m "descripció del canvi"
# Quan la tasca és llesta, fusionar a main
git switch main
git pull origin main
git merge feature/cerca
git push origin main
# Neteja
git branch -d feature/cerca
Commit directe o feature branches?
| Commit directe a main | Feature branches | |
|---|---|---|
| Complexitat git | Baixa | Mitjana |
| Risc de conflictes | Baix (si sincronitzen sovint) | Mig (si les branques viuen més de 3 dies) |
| Aïllament del treball | Cap: un error afecta tothom | Alt: els errors queden a la branca |
| Quan triar-les | Sense CI/CD, o amb trunk-based development en un equip molt petit | Gairebé sempre |
El motiu, que té més a veure amb el CI/CD que amb la mida de l’equip, el veurem a Quan val la pena.
Les branques de curta durada (2 o 3 dies) funcionen bé. Les de llarga durada (més d’una setmana) divergeixen molt de main i els merges es compliquen. La regla pràctica: una tasca, una branca, fusiona ràpid.
Fixa’t, però, que en l’exemple anterior fusiones la teva pròpia branca quan creus que està llesta. Ningú més no mira el codi abans que arribi a main. Aquest és el forat que omplen les pull requests.
Pull requests i merge requests
Una pull request (PR) és una petició per fusionar una branca en una altra, normalment una feature branch a main, que queda oberta perquè l’equip la revisi abans d’acceptar-la. GitHub, Bitbucket, Gitea i Forgejo en diuen pull request; GitLab en diu merge request (MR). És exactament el mateix concepte amb dos noms, i convé reconèixer-los tots dos: els trobaràs constantment en ofertes de feina, documentació i converses d’equip. En aquest document farem servir “PR”.
Una PR agrupa en una sola pàgina web tot el que cal per decidir si un canvi entra:
- Branca origen i branca destí: què es vol fusionar i on.
- Descripció: què fa el canvi i per què, escrita per qui el proposa.
- Diff i llista de commits: què canvia exactament.
- Comentaris de revisió: converses lligades a línies concretes del codi.
- Checks de CI: el resultat dels tests i les validacions automàtiques. La integració contínua (continuous integration, CI) és un servei que executa aquestes comprovacions sol cada vegada que puges canvis; en tornarem a parlar a CI/CD.
- Aprovacions i botó de merge: la decisió final.
Avui és la pràctica estàndard del treball en equip. La mecànica de fons, però, és independent de la plataforma: primer la veurem amb git pur per entendre què passa realment per sota.
Revisió abans del merge
El principi és senzill: separar qui proposa canvis de qui els accepta. Un desenvolupador treballa a la seva branca i, quan la tasca és llesta, demana a un responsable que revisi i integri els canvis a la branca principal. El responsable pot:
- Revisar el diff dels canvis proposats.
- Demanar correccions si cal.
- Acceptar i fer el merge quan tot és correcte.
Això afegeix una capa de revisió que millora la qualitat del codi i evita que canvis no revisats arribin a la branca principal.
El flux amb git pur
Aquest flux no requereix cap eina especial, només git i una convenció d’equip:
1. Treballes a la teva branca i la puges al repositori remot:
git switch -c feature/cerca
# ... treballa, fa commits ...
git push -u origin feature/cerca
El -u associa la branca local amb la remota (estableix l’upstream), de manera que les properes vegades n’hi ha prou amb git push.
2. Avises el responsable (per correu, xat o qualsevol canal) que la branca està llesta per revisar.
3. El responsable revisa els canvis des del seu repositori local:
git fetch origin
git log --oneline main..origin/feature/cerca # quins commits hi ha
git diff main..origin/feature/cerca # què canvien
4. Si cal demanar correccions, el responsable t’ho comunica. Fas els canvis a la mateixa branca, commit i git push (ja no cal especificar el remot ni la branca gràcies al -u inicial), i el responsable torna a revisar.
5. Quan els canvis són acceptats, el responsable fa el merge:
git switch main
git pull origin main
git merge origin/feature/cerca
git push origin main
# Neteja de la branca remota
git push origin --delete feature/cerca
6. Tu sincronitzes i neteges en local:
git switch main
git pull origin main
git branch -d feature/cerca
El mateix flux a la plataforma
Una PR no inventa res de nou: automatitza i deixa per escrit els passos anteriors.
| Pas amb git pur | Amb una PR |
|---|---|
| 1. Pujar la branca | Igual: git push -u origin feature/cerca |
| 2. Avisar el responsable | Obrir la PR, amb una descripció i els revisors assignats |
3. Revisar amb git log i git diff | La plataforma mostra els commits i el diff, i el CI hi executa els tests sol |
| 4. Demanar correccions | Comentaris a les línies concretes; cada push a la branca actualitza la PR |
| 5. Fer el merge | Botó de merge, que es pot bloquejar fins que hi hagi aprovacions i el CI passi |
| 6. Netejar | La plataforma pot esborrar la branca remota automàticament; en local, igual que abans |
La diferència important no és la comoditat, sinó que la revisió queda registrada: d’aquí a un any, qualsevol persona podrà trobar la PR que va introduir una línia i llegir per què es va fer i què se’n va discutir.
Revisar en un worktree
Llegir el diff no sempre és prou: de vegades vols executar el codi de la PR. Però si estàs a mig fer feature/cerca i una companya et demana que revisis feature/login, canviar de branca t’obliga a fer commit o stash de la feina a mitges.
Un worktree (directori de treball enllaçat) evita aquest pas: és un segon working directory del mateix repositori, en una altra carpeta i amb una altra branca. Comparteix el .git amb la carpeta principal (commits, branques i configuració), però té els seus propis arxius, staging area i HEAD.
git fetch origin
git worktree add ../botiga-login origin/feature/login
# a ../botiga-login: compila, executa els tests, prova-ho
git worktree remove ../botiga-login
Com que només el vols mirar, el worktree queda en estat detached HEAD, sense crear cap branca local. La teva carpeta principal continua a feature/cerca, intacta. Tingues en compte que el worktree només conté els arxius versionats: dependències, builds i arxius .env s’han de preparar com en un clone nou.
Els worktrees són també la base per fer treballar agents de programació en paral·lel sense que toquin la teva còpia de treball, com s’explica a Git amb agents.
Permisos sobre branques
Per reforçar aquest flux, es poden configurar permisos d’escriptura sobre les branques del repositori remot. Per exemple, restringir l’escriptura a main a un sol usuari o a un grup reduït. D’aquesta manera, els desenvolupadors poden pujar les seves feature branches però no poden fer push directament a main: només s’hi arriba a través d’una PR revisada.
Això converteix una convenció organitzativa en una restricció tècnica. La majoria de servidors git (inclosos els auto-allotjats) permeten configurar aquests permisos. A GitHub i GitLab es fa amb les regles de protecció de branca (branch protection rules), que típicament es configuren per:
- exigir que els canvis arribin via PR;
- requerir un nombre mínim d’aprovacions;
- no permetre el merge fins que els checks de CI passin;
- prohibir el push forçat, perquè ningú no pugui reescriure la història de
main.
Quan val la pena
Gairebé sempre, encara que treballis sol, perquè avui gairebé tots els projectes tenen CI/CD. El CI ha de provar el codi abans que arribi a main, i això només és possible si el codi espera en una branca i hi entra per una PR. Amb un push directe, els tests s’executen quan el codi ja és a main; amb CD (desplegament automàtic de cada canvi a main), a més, ja s’ha desplegat.
Si treballes sol, obres la PR, esperes que el CI passi i la fusiones tu mateix (el mode Show de Ship / Show / Ask). En equip, la PR també serveix per saber què fan els altres.
Sense CI/CD, o amb trunk-based development en un equip molt petit, el commit directe a main és viable, però cada cop és menys habitual.
Commits fàcils de revisar
Ara que la teva feina passarà per una revisió, els commits deixen de ser només per a tu: són el que llegirà el revisor. Una PR és tan fàcil de revisar com ho són els seus commits. Les dues pràctiques següents fan que el teu company entengui la teva feina sense haver de preguntar-te res.
Missatges de commit
Un bon missatge de commit permet al teu company entendre el canvi sense llegir el diff. Dues convencions habituals:
Imperatiu simple (mínim de fricció):
git commit -m "add product search endpoint"
git commit -m "fix null check in price filter"
git commit -m "remove unused imports"
Regla: comença amb un verb en imperatiu. Descriu què fa el commit, no el que has fet tu. Menys de 72 caràcters.
Conventional Commits (més estructurat):
git commit -m "feat: add product search endpoint"
git commit -m "fix: handle empty search query"
git commit -m "test: add unit tests for search filters"
git commit -m "docs: update README with search examples"
git commit -m "chore: update dependencies"
Prefixos: feat (nova funcionalitat), fix (correcció), test (tests), docs (documentació), chore (manteniment), refactor (refactorització sense canvi de comportament).
Com que el format és estructurat, les eines el poden llegir: a partir dels commits es pot generar el changelog (la llista de canvis de cada versió) o decidir automàticament el número de la versió següent en el pipeline de CI/CD, que veurem més endavant.
| Imperatiu simple | Conventional Commits | |
|---|---|---|
| Fricció d’escriptura | Baixa | Mitjana (cal recordar el prefix) |
| Llegibilitat del log | Bona | Molt bona |
| Compatible amb eines de changelog | No | Sí |
Commits atòmics
Un commit atòmic conté un sol canvi lògic, i el codi ha de funcionar després de cada commit. Això contrasta amb fer un sol commit gran al final del dia amb tots els canvis barrejats.
Per què importa? Quan alguna cosa falla, els commits atòmics fan evident quin canvi ha causat el problema:
# Commit gran: on és el problema?
$ git log --oneline -1
a3f9b12 "add search index, filters, endpoint and tests"
# Commits atòmics: el problema és al segon commit
$ git log --oneline -4
a3f9b12 "add search endpoint"
def5678 "add price and category filters" ← falla aquí
c72a3f8 "add product search index"
5e8d1a0 "add search service skeleton"
També fan la revisió més fàcil: el revisor pot seguir la PR commit a commit, com una història en capítols, en lloc d’enfrontar-se a un sol diff enorme.
Regla pràctica: fes commit de cada unitat lògica de treball per separat, ajudant-te de l’staging area per triar què hi entra. Si el codi no està llest, utilitza git stash per guardar-lo temporalment sense fer commit.
Integrar la branca a main
Quan la teva feature està llesta, queden dos passos: posar la branca al dia amb main abans de la revisió, i triar com s’hi fusiona quan s’aprova.
Posar-la al dia amb rebase
Mentre treballes a feature/cerca, main avança amb les PR dels teus dos companys. Abans de demanar la revisió, et convé posar la teva branca al dia, perquè el revisor vegi la teva feina sobre el codi actual. Hi ha dues maneres de fer-ho, merge i rebase, i per triar bé cal entendre-les.
Tant el merge com el rebase combinen feina, però d’una manera molt diferent: el merge conserva les dues històries i les uneix amb un commit nou amb dos pares; el rebase, en canvi, reescriu els teus commits perquè quedin com si els haguessis escrit a sobre d’una altra base.
La intuïció: imagina els teus commits enganxats amb post-it. El merge els deixa on són i hi pinta una línia que els connecta amb l’altra branca. El rebase els despenja, mou la base de la branca fins a un altre punt, i els torna a enganxar a sobre. Com que el resultat són commits “nous” (mateix contingut, hashes diferents), val la regla d’or de reescriure història: només sobre feina que encara no has compartit.
Si vas fent merge de main a la teva branca per estar al dia, deixes una bombolla de merge cada cop (“Merge branch ‘main’ into feature/cerca”) i acabes amb una història enrevessada que costa de revisar. El rebase ho evita:
git switch feature/cerca
git fetch
git rebase origin/main
El resultat és una història lineal i neta, com si haguessis començat la feature ara mateix. Hi ha tres beneficis que es combinen:
- Revisió neta: el revisor veurà la teva feina com una llista de commits per damunt del
mainactual, sense soroll de manteniment. - Integració primerenca: desenvolupes contra el codi real d’ara, així que si
mainha canviat el nom d’una funció, ha modificat una signatura o ha introduït un bug, ho descobreixes immediatament en local i no el dia del merge. Compte: el rebase només resol conflictes textuals; els conflictes semàntics no els detecta, així que cal tornar a passar els tests després del rebase per confirmar que tot encaixa. - Conflictes més suaus: la quantitat total no canvia (vénen de tocar les mateixes línies), però l’experiència sí: els resols a poc a poc, amb el context d’un sol commit, i no en un únic xoc gran el dia del merge final. Quan la PR finalment s’integra, el merge a
mainpot ser un fast-forward net, segons el mètode de fusió que triï l’equip.
Compte: després d’un rebase, els commits són nous. Si ja havies pujat la branca, el següent push caldrà fer-lo amb
--force-with-lease. Sobre la teva pròpia feature branch això és acceptable, perquè ningú més no hi treballa. Però si algun company també hi fa commits, parla-hi abans de reescriure-la.
Maneres de fusionar una PR
Quan la PR s’accepta, què els passa, als teus commits? Les plataformes deixen triar com s’incorporen a main. Els noms són els de GitHub; GitLab ofereix opcions equivalents.
| Mètode | Què passa a main | Quan triar-lo |
|---|---|---|
| Create a merge commit | Tots els commits de la branca, més un commit de merge amb dos pares | Vols conservar la història completa i saber quins commits venien junts |
| Squash and merge | Un sol commit nou amb tots els canvis de la branca | Els commits de la branca són de feina a mitges (“wip”, “fix typo”); a main en queda un de net per tasca |
| Rebase and merge | Els commits de la branca, reaplicats un a un sobre main, sense commit de merge | Els commits ja són atòmics i vols una història lineal |
És la mateixa distinció entre fast-forward i commit de merge que vam veure a Workflow Git, ara decidida per l’equip. Molts equips fan servir squash per defecte: és el més senzill i deixa main amb un commit per PR, fàcil de revertir si alguna cosa falla. Això no fa inútils els commits atòmics: continuen a la PR, i és allà on han facilitat la revisió.
Fluxos de treball de la indústria
Fins aquí hem vist peces soltes: branques de curta durada, PR, protecció de branques, commits fàcils de revisar i com integrar la branca a main. A la pràctica, cada equip les combina en un flux de treball (workflow), un acord sobre quines branques existeixen, qui hi pot escriure i com arriba el codi a producció. Alguns d’aquests acords s’han fet tan populars que tenen nom propi. Martin Fowler, en el seu article de referència sobre branques, distingeix precisament entre els patrons (les peces) i les polítiques que els combinen (aquests fluxos).
Els que convé reconèixer són GitHub flow i trunk-based development, els habituals avui, i Git flow, més antic però encara present en molts projectes i tutorials. Tancarem amb GitLab flow, una variant de GitHub flow per a quan hi ha diversos entorns.
GitHub flow
El GitHub flow el va descriure Scott Chacon, de GitHub, el 2011. Té una sola regla central: tot el que és a main es pot desplegar. No hi ha cap altra branca permanent. Tota la feina es fa en feature branches, i els passos són els que ja has fet amb feature/cerca:
- Crear una branca des de
mainamb un nom descriptiu. - Fer-hi commits i pujar-la sovint.
- Obrir una PR quan vols feedback o creus que està llesta.
- Atendre els comentaris de revisió amb nous commits a la mateixa branca.
- Fer el merge a
mainquan la PR està aprovada i el CI passa. - Esborrar la branca. Com que
mainés sempre desplegable, el merge es pot desplegar tot seguit.
Al diagrama, la teva cerca avança en paral·lel amb el login que fa una companya. Cada branca entra a main per la seva PR, i main només rep feina revisada:
gitGraph
commit id: "inici"
branch feature/login
checkout feature/login
commit id: "formulari"
commit id: "validació"
checkout main
branch feature/cerca
checkout feature/cerca
commit id: "cerca"
checkout main
merge feature/login id: "PR #12"
checkout feature/cerca
commit id: "filtres"
checkout main
merge feature/cerca id: "PR #13"
Fixa’t que GitHub flow no és res de nou: és la suma de feature branches, PR, protecció de main i CI. Aquesta senzillesa és precisament el que l’ha fet el flux més estès.
Trunk-based development
En el trunk-based development tothom integra a una sola branca, el trunk (main), com a mínim un cop al dia, i l’equip evita qualsevol altra branca de llarga durada. Es pot fer amb commits directes a main en equips molt petits, sempre que cadascú passi els tests en local abans de pujar (la protecció depèn llavors de la disciplina de cadascú, no d’una comprovació automàtica), però en equips reals sol consistir en branques de molt curta durada (hores, com a molt un parell de dies) que entren via PR darrere d’un CI exigent.
La diferència amb GitHub flow és de grau, no de mecànica: GitHub flow no diu quant ha de durar una branca, i trunk-based development diu que molt poc. Integrar tan sovint fa que els conflictes siguin petits i que el codi de tothom es provi junt constantment, que és la idea de la integració contínua.
Però què passa si la cerca de productes triga dues setmanes i la branca ha de durar un dia? El codi s’integra a main a trossos, desactivat. Els feature flags (interruptors de funcionalitat) permeten tenir a producció codi que encara no s’executa, i activar-lo quan està complet. En parlem a estratègies de desplegament.
El preu és que cal una bona bateria de tests automàtics: sense la xarxa del CI, integrar tan sovint seria temerari.
Git flow
El Git flow el va proposar Vincent Driessen el 2010, i durant anys va ser el model de branques. Fa servir dues branques permanents:
main: només conté versions publicades, cadascuna marcada amb un tag.develop: on s’integra la feina per a la propera versió.
I tres tipus de branques de suport:
feature/*: surten dedevelopi hi tornen.release/*: surten dedevelopquan es prepara una versió; només admeten correccions, i es fusionen amain(amb el tag) i adevelop.hotfix/*: surten demainper corregir un error urgent en producció, i es fusionen amaini adevelop.
gitGraph
commit id: "inici"
branch develop
checkout develop
commit id: "base"
branch feature/cerca
checkout feature/cerca
commit id: "cerca"
checkout develop
merge feature/cerca
branch release/1.0
checkout release/1.0
commit id: "ajustos 1.0"
checkout main
merge release/1.0 tag: "v1.0"
checkout develop
merge release/1.0
checkout main
branch hotfix/1.0.1
checkout hotfix/1.0.1
commit id: "correcció"
checkout main
merge hotfix/1.0.1 tag: "v1.0.1"
checkout develop
merge hotfix/1.0.1
Git flow encaixa quan el programari es publica en versions explícites i n’has de mantenir més d’una alhora: una aplicació d’escriptori, una llibreria, una app mòbil que passa per la revisió de la botiga. Per a una aplicació web com la botiga en línia, que es pot desplegar diverses vegades al dia, en canvi, és massa pesat. L’autor mateix ho va reconèixer el 2020 en una nota afegida a l’article original: per a equips que fan lliurament continu, recomana un flux més simple com GitHub flow.
GitLab flow
El GitLab flow és una variant de GitHub flow per quan desplegar no és instantani o hi ha diversos entorns. Manté main i les feature branches, i hi afegeix branques d’entorn (per exemple pre-production i production): els canvis sempre flueixen en una sola direcció, de main cap a producció, i cada branca reflecteix el que hi ha desplegat en aquell entorn. Si cal mantenir versions publicades, es fan servir branques de release (una per versió, per exemple v1 i v2) en lloc de les d’entorn.
Quin triar
| Flux | Branques permanents | Feature branches | Quan es desplega | Encaixa amb |
|---|---|---|---|---|
Commit directe a main | main | No se’n fan servir | Quan es vulgui | Equips de 2 persones, pràctiques |
| GitHub flow | main | Una per tasca, idealment curtes (el flux no en fixa la durada) | Després de cada merge | La majoria de projectes web i serveis |
| Trunk-based development | main | Opcionals i molt curtes: hores, com a molt un parell de dies | Contínuament | Equips amb CI i tests molt sòlids |
| GitLab flow | main + branques d’entorn | Una per tasca, com a GitHub flow | En promocionar a la branca d’entorn | Diversos entorns o desplegaments amb validació manual |
| Git flow | main + develop | Surten de develop i poden durar tot el cicle d’una release (a més, hi ha branques release/* i hotfix/*) | En tancar una release | Programari amb versions i diverses versions mantingudes |
Si no tens cap motiu concret per a una altra cosa, tria GitHub flow: és el que trobaràs a la majoria d’equips, el que les plataformes suporten millor, i el punt de partida natural cap a trunk-based development.
CI/CD
Ja hem vist que la integració contínua (CI) executa els tests de cada PR. Sovint va acompanyada del CD, que porta el codi fins a producció automàticament, amb una aprovació manual (lliurament continu) o sense (desplegament continu). Els conceptes s’expliquen a DevOps; aquí ens interessa com s’hi connecta el que fas amb git.
El recorregut d’un canvi
Seguim la cerca de productes des que la puges fins que arriba als usuaris, en un equip que fa servir GitHub flow:
| Què fas | Esdeveniment git | Què s’executa |
|---|---|---|
git push de feature/cerca | Push a una feature branch | Compilació i tests |
| Obres la PR #13 | Obertura d’una PR | Tots els tests; el resultat apareix com a checks a la PR |
| Puges un commit per respondre la revisió | Actualització de la PR | Els mateixos tests, de nou |
| Prems el botó de merge | Push a main | Build i desplegament a producció |
Tu només has fet operacions git normals, i la resta ha passat sola. Cadascuna d’aquestes execucions és un pipeline: una seqüència de passos automàtics que es posa en marxa quan passa un esdeveniment git.
Fixa’t en l’última fila: fer el merge des del botó de la plataforma no és cap git push teu, però per al repositori és un push a main. Qualsevol acció sobre el repositori remot pot engegar un pipeline, també les que fas des del navegador.
Disparadors segons el flux
El recorregut anterior és el de GitHub flow. En altres fluxos, l’esdeveniment que desplega és un altre, perquè cada flux dona un significat diferent als esdeveniments git:
| Flux | Què valida el CI | Què desplega |
|---|---|---|
| GitHub flow | Cada PR | El merge a main |
| Trunk-based development | Cada PR o push a main | Cada canvi a main, contínuament |
| GitLab flow | Cada PR a main | El merge a la branca d’entorn (per exemple, production) |
| Git flow | Les PR a develop | El push d’un tag de versió a main |
Configuració dels pipelines
Res d’això passa per defecte: l’equip decideix què s’executa amb cada esdeveniment i ho escriu en fitxers YAML dins del mateix repositori. A GitHub (GitHub Actions), cada pipeline és un fitxer anomenat workflow dins de la carpeta .github/workflows/. El recorregut de la cerca en podria fer servir dos:
.github/workflows/
├── tests.yml ← en cada push i en cada PR
└── deploy.yml ← només en els push a main
Així podria ser deploy.yml per a la botiga, feta en Java:
name: Deploy
on:
push:
branches: [main] # only when main changes, e.g. after a merge
jobs:
deploy:
runs-on: ubuntu-latest # a clean machine provided by GitHub
steps:
- uses: actions/checkout@v7 # get the code at the merged commit
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: "25"
- run: ./mvnw package # compile, run the tests, build the jar
- run: ./scripts/deploy.sh # copy the jar to the server and restart it
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
Llegit de dalt a baix: el bloc on diu que el workflow s’engega amb cada push a main. Llavors GitHub arrenca una màquina neta, hi descarrega el codi, instal·la Java, compila i passa els tests, i executa l’script de desplegament. Cada pas és una ordre (run) o una acció (uses), una peça reutilitzable que ja ha publicat algú altre. Si un pas falla, els següents no s’executen: un commit que trenca els tests no arriba a producció. DEPLOY_TOKEN és la credencial per accedir al servidor, guardada com a secret de la plataforma i no al fitxer, com veurem a les bones pràctiques amb CI.
Els esdeveniments més habituals al bloc on:
| Esdeveniment | Quan |
|---|---|
push | Push de commits o tags |
pull_request | Obertura o actualització d’una PR |
merge_group | Entrada d’una PR a la merge queue |
release | Publicació d’una release a la plataforma |
schedule | A una hora programada |
workflow_dispatch | Execució manual des de la plataforma |
GitLab (GitLab CI/CD) segueix la mateixa idea amb un únic fitxer, .gitlab-ci.yml, a l’arrel del repositori, on cada tasca (job) porta les seves condicions.
Com que són fitxers del repositori, els canvis al pipeline passen pel mateix procés que el codi: commits, PR i revisió.
Bones pràctiques amb CI
- Prova en local abans de fer push. Cada push engega el pipeline. Si els tests ja fallen en local, t’estalvies esperar el CI per saber-ho, i estalvies temps de CI a tot l’equip.
- Si el CI falla a la teva PR, corregeix a la mateixa branca. Obre el detall del check, llegeix el log del pas que ha fallat, arregla-ho i fes un commit nou a
feature/cerca. En fer push, la PR s’actualitza i els tests tornen a córrer. No facis el merge amb els checks en vermell, encara que la regla de protecció t’ho permeti. - Un
maintrencat afecta tothom. Si arriba amaincodi que no compila o que trenca els tests, totes les branques que en surten hereten l’error, i si el merge desplega, l’error arriba a producció. Per aixòmaines protegeix i només s’hi entra via PR, com hem vist a Quan val la pena. - Les credencials no van al YAML. Per desplegar, el pipeline necessita contrasenyes o claus d’accés, però el fitxer el pot llegir qualsevol persona amb accés al repositori. Guarda-les com a secrets de la plataforma (a GitLab, variables de CI/CD) i referencia-les pel nom des del YAML.
Publicació de versions
Quan el desplegament depèn d’un tag, com a Git flow, algú ha de crear-lo. Es pot fer a mà o deixar-ho al pipeline.
A mà, crear un tag és publicar. Crea’l de forma deliberada i sobre un commit que ja sigui a main. Si el crees sobre un commit local que no has pujat, en fer push del tag el pipeline desplegarà codi que el CI no ha validat.
git switch main
git pull ← agafa el commit ja validat
git tag -a v1.0 -m "versió 1"
git push origin v1.0 ← el CI desplega la v1.0
Automàticament, si l’equip escriu els missatges amb Conventional Commits. A cada merge a main, el pipeline mira els commits que hi ha des de l’últim tag i decideix el número de la versió següent:
- amb algun
fixi capfeat, puja l’últim número:1.4.2passa a1.4.3; - amb algun
feat, puja el del mig:1.4.2passa a1.5.0; - amb un canvi incompatible (marcat amb
BREAKING CHANGE), puja el primer:1.4.2passa a2.0.0.
Eines com semantic-release fan tot aquest pas: calculen el número, creen el tag, generen el changelog i publiquen la versió. Així la decisió de publicar ja no depèn de recordar crear un tag, sinó de com has escrit els commits.
Pràctiques actuals amb PR
Les PR han resolt el problema de la revisió, però n’han creat de nous: esperes llargues per a una aprovació, PR enormes que ningú no vol revisar, i main trencat per dues PR que per separat eren correctes. Aquestes són les respostes més esteses.
Ship / Show / Ask
No tots els canvis necessiten el mateix nivell de revisió. Ship / Show / Ask, proposat per Rouan Wilsenach, classifica cada canvi en tres categories:
- Ship (envia): el canvi va directe a
main, sense PR. Per a coses trivials: corregir una errada al README o a un comentari. - Show (mostra): obres una PR perquè l’equip la vegi, però la fusiones tu mateix quan el CI passa, sense esperar aprovació. La conversa, si n’hi ha, ve després.
- Ask (pregunta): obres una PR i esperes la revisió abans de fusionar. Per a canvis on no estàs segur de l’enfocament o que toquen parts delicades, com la primera versió de la teva cerca.
La idea de fons és que la revisió és una eina, no un peatge: l’equip decideix en cada cas quanta en cal, en lloc d’aplicar sempre el màxim.
Merge queues
Imagina dues PR que, cadascuna per separat, passen el CI contra main. A la del login, la teva companya canvia el nom d’una funció; a la teva, la cerca afegeix una crida a aquella funció amb el nom antic. Quan es fusionen totes dues, main deixa de compilar: és un conflicte semàntic que cap de les dues PR podia detectar sola.
Una merge queue (cua de merge) ho evita. En lloc de fusionar directament, les PR aprovades entren en una cua, i el sistema prova cadascuna combinada amb main i amb totes les PR que té al davant. Només es fusiona si aquesta combinació passa el CI. GitHub l’anomena merge queue i GitLab, merge trains. És habitual en repositoris amb molts merges al dia, perquè garanteix que main es mantingui sempre en verd, és a dir, amb tots els checks del CI passant.
Stacked PRs
Una PR gran costa de revisar, i una PR que costa de revisar s’eternitza. Però de vegades una funcionalitat necessita molts canvis que depenen els uns dels altres. Les stacked PRs (PR apilades) divideixen el canvi en una cadena de PR petites, on cadascuna parteix de l’anterior en lloc de main: per a la cerca, primer l’índex, a sobre els filtres i a sobre l’endpoint. Cada capa es revisa per separat, i quan totes estan aprovades es fusionen en ordre.
Fa anys que la tècnica existeix amb eines externes, però ha guanyat pes amb l’augment de codi generat amb ajuda d’IA: es produeix més codi del que les persones poden revisar, i trossejar-lo en peces petites és la manera de mantenir la revisió útil. Des de juliol de 2026, GitHub les suporta de manera nativa, en fase de proves pública (public preview).
Per començar
Si has de muntar el flux d’un projecte d’equip, aquest és un punt de partida raonable que pots anar ajustant:
- Adopta GitHub flow:
mainsempre desplegable i una feature branch per tasca. - Protegeix
main: només s’hi arriba per PR, amb una aprovació i el CI en verd. - Configura un CI mínim que executi els tests a cada PR.
- Fes commits atòmics amb missatges clars, i posa la branca al dia amb rebase abans de demanar revisió.
- Mantén les branques curtes: si una tasca s’allarga més de dos o tres dies, divideix-la.
Referències
- GitHub Docs: GitHub flow
- Scott Chacon: GitHub Flow (2011)
- Vincent Driessen: A successful Git branching model (2010)
- Trunk Based Development
- GitLab: What is GitLab Flow?
- Martin Fowler: Patterns for Managing Source Code Branches
- Rouan Wilsenach: Ship / Show / Ask
- GitHub Docs: Managing a merge queue
- GitHub Docs: Workflows
- GitHub Docs: Events that trigger workflows
- GitLab Docs: CI/CD YAML syntax reference
- GitLab Docs: Merge trains
- GitHub Changelog: Stacked pull requests are now in public preview
- Conventional Commits
- semantic-release
- Atlassian: Comparing workflows