Les branques són barates, i aquesta és la seva virtut. També és el seu problema: quan crear-ne una costa zero, se'n creen moltes, i al cap d'uns mesos el repositori de l'Ana té branques de funcionalitats ja integrades, branques d'experiments que ningú no recorda, branques amb noms com prova o apany2 i alguna que porta sis setmanes sense un sol commit.

Un repositori amb quaranta branques de les quals només tres són vives no és un problema tècnic —Git n'aguanta milers sense despentinar-se—, però sí un problema humà: ningú no sap quina és quina, ningú no s'atreveix a esborrar res per por de perdre feina i l'autocompletat deixa de ser útil.

Aquesta lliçó és la caixa d'eines per mantenir això sota control: llistar branques amb la informació que necessites, saber quines es poden esborrar sense perdre res, reanomenar, esborrar amb seguretat i posar-los noms que diguin alguna cosa. És la lliçó menys espectacular del mòdul i probablement la que més vegades aplicaràs.

Contingut

  1. Llistar branques: git branch i les seves variants
  2. --merged i --no-merged: què es pot esborrar sense perdre res
  3. Llistats a mida amb --sort i --format
  4. Reanomenar branques amb -m
  5. Esborrar branques: -d davant de -D
  6. Quan l'esborrat segur falla
  7. Convencions de noms
  8. Quins noms admet Git: git check-ref-format
  9. Higiene: detectar branques obsoletes
  10. Tancament del mòdul

  1. Llistar branques: git branch i les seves variants

L'ordre base ja la coneixes:

git branch
  correccio/missatge-llista-buida
  documentacio/actualitzar-notes
  experiment/emmagatzematge-indexeddb
  funcionalitat/comptador-tasques
  funcionalitat/exportar-csv
  funcionalitat/filtre-pendents
  funcionalitat/ordre-alfabetic
  neteja/esborrar-notes
* main
  prova

Deu branques. L'asterisc marca l'actual. Ordenades alfabèticament, sense més informació. És un punt de partida pobre: no saps quines estan integrades, ni quines porten mesos aturades.

-v: què hi ha a la punta de cadascuna

git branch -v
  correccio/missatge-llista-buida      6d3f8b2 Mostra un missatge quan el llistat és buit
  documentacio/actualitzar-notes       3f7a9c1 Actualitza les notes internes amb el flux nou
  experiment/emmagatzematge-indexeddb  5e8b1d4 Desa les tasques a IndexedDB
  funcionalitat/comptador-tasques      9d1e4b7 Marca les tasques com a completades en fer clic
  funcionalitat/exportar-csv           e9a2c5f Ara sí
  funcionalitat/filtre-pendents        b2e6d3f Corregeix el focus del camp després d'afegir una tasca
  funcionalitat/ordre-alfabetic        a1e5c93 Mostra les tasques ordenades alfabèticament
  neteja/esborrar-notes                7f3c9a2 Esborra les notes internes, ja obsoletes
* main                                 c2a8f1e Fusiona el missatge de llista buida
  prova                                8b6d3c2 Afegeix els estils base del llistat

Ja es pot començar a raonar. Fixa't en prova: apunta a 8b6d3c2, un commit antiquíssim del principi del projecte. És una branca morta que es va crear i no es va fer servir mai.

Hi ha una variant doble:

git branch -vv

Hi afegeix, entre claudàtors, la branca de seguiment de cadascuna: amb quina branca del repositori remot està aparellada i quants commits porta per davant o per darrere. Com que en aquest mòdul tot passa en un únic repositori local, encara no hi ha res per mostrar; -vv cobrarà tot el sentit al mòdul 4, quan la feina comenci a viatjar entre màquines.

Altres opcions de llistat

# Només branques que contenen un commit concret
git branch --contains a1e5c93

# Només branques que NO el contenen
git branch --no-contains a1e5c93

# Filtrar per patró (admet comodins)
git branch --list 'funcionalitat/*'

# Incloure també les branques remotes (mòdul 4)
git branch -a

# Només les remotes
git branch -r

--contains és especialment útil per respondre a «a quines branques és aquest arranjament?»:

git branch --contains 6d3f8b2
  correccio/missatge-llista-buida
* main

L'arranjament del missatge de llista buida és a la seva branca original i a main. A cap altra.

  1. --merged i --no-merged: què es pot esborrar sense perdre res

Aquestes dues opcions són el cor de la higiene de branques.

git branch --merged
  correccio/missatge-llista-buida
  experiment/emmagatzematge-indexeddb
  funcionalitat/comptador-tasques
  funcionalitat/filtre-pendents
  funcionalitat/ordre-alfabetic
  neteja/esborrar-notes
* main
  prova

El significat exacte, i convé ser precís perquè genera confusió: --merged llista les branques la punta de les quals és assolible des de la branca actual. Dit d'una altra manera: tots els seus commits ja són a l'historial de main.

Traduït a la pràctica: aquestes branques es poden esborrar sense perdre ni un sol commit.

Dos casos mereixen comentari:

  • prova hi apareix perquè la seva punta és 8b6d3c2, un commit del principi del projecte que òbviament és a main. No aportava res, i per això consta com a fusionada.
  • experiment/emmagatzematge-indexeddb també hi apareix, encara que el seu codi no va arribar mai al projecte: la vam tancar a la lliçó 03-04 amb git merge -s ours, que crea el commit de fusió sense portar-ne el contingut. Aquell era precisament l'objectiu d'aquella estratègia: que la branca deixés de figurar com a pendent.

I ara l'altra cara:

git branch --no-merged
  documentacio/actualitzar-notes
  funcionalitat/exportar-csv

Aquestes branques tenen commits que main no té. Esborrar-les deixaria aquests commits sense cap referència que els assoleixi. Per què hi és cadascuna:

  • documentacio/actualitzar-notes: vam resoldre el seu conflicte modify/delete a favor de l'esborrat del fitxer, així que el seu commit no va arribar mai a main. És correcte que aparegui aquí.
  • funcionalitat/exportar-csv: la vam integrar amb squash. El seu contingut és a main, però els seus sis commits originals no. Git diu la veritat: des del punt de vista del graf, no està fusionada.

Aquest últim cas és el parany més habitual: una branca integrada amb squash sempre apareix a --no-merged. Si el teu equip fa servir squash sistemàticament, --merged deixa de ser un criteri fiable per esborrar i cal portar el compte d'una altra manera.

Comparar contra una altra branca

Per defecte, les dues opcions comparen contra HEAD. Se'ls pot indicar una altra referència:

# Branques fusionades a main, encara que jo no sigui a main
git branch --merged main

# Branques la feina de les quals ja és a la versió 1.2
git branch --merged v1.2.0

# Branques sense integrar a main
git branch --no-merged main

És la manera correcta de fer-les servir en scripts, perquè no depèn d'on estiguis situat.

El patró de neteja

Aquest és l'idiom que veuràs a tot arreu i que convé entendre peça a peça:

git branch --merged main | grep -v '^\*' | grep -v ' main$' | xargs -r git branch -d
  • git branch --merged main: les candidates.
  • grep -v '^\*': treu la línia de la branca actual (la de l'asterisc).
  • grep -v ' main$': treu main de la llista, no fos cas que intentés esborrar-se a si mateixa.
  • xargs -r git branch -d: esborra cadascuna amb l'esborrat segur (-r evita executar res si la llista ve buida).

Abans d'executar-lo, revisa sempre la llista traient l'últim tram:

git branch --merged main | grep -v '^\*' | grep -v ' main$'

Un consell important: fes servir -d i mai -D en una ordre automàtica com aquesta. -d es nega si alguna cosa no quadra; -D esborra sense preguntar.

  1. Llistats a mida amb --sort i --format

L'ordre alfabètic no és el més útil. El que gairebé sempre vols saber és quines branques són vives, i això és una qüestió de dates.

git branch --sort=-committerdate
* main
  correccio/missatge-llista-buida
  funcionalitat/ordre-alfabetic
  documentacio/actualitzar-notes
  neteja/esborrar-notes
  funcionalitat/exportar-csv
  funcionalitat/filtre-pendents
  funcionalitat/comptador-tasques
  experiment/emmagatzematge-indexeddb
  prova

El guionet davant de committerdate significa ordre descendent: el més recent a dalt. Les de baix són les candidates a desaparèixer.

Camps d'ordenació habituals:

Camp Ordena per
committerdate Data de l'últim commit de la branca
authordate Data d'autoria de l'últim commit
refname Nom (l'ordre per defecte)
-committerdate Data, de més recent a més antiga

I amb --format es construeix un llistat a mida, fent servir els mateixos marcadors de git for-each-ref:

git branch --sort=-committerdate \
  --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) | %(committerdate:relative) | %(authorname) | %(contents:subject)'
* main | fa 2 hores | Ana Ferrer | Fusiona el missatge de llista buida
  correccio/missatge-llista-buida | fa 3 hores | Bruno Salas | Mostra un missatge quan el llistat és buit
  funcionalitat/ordre-alfabetic | fa 5 hores | Ana Ferrer | Mostra les tasques ordenades alfabèticament
  documentacio/actualitzar-notes | fa 2 dies | Bruno Salas | Actualitza les notes internes amb el flux nou
  neteja/esborrar-notes | fa 2 dies | Ana Ferrer | Esborra les notes internes, ja obsoletes
  funcionalitat/exportar-csv | fa 6 dies | Bruno Salas | Ara sí
  funcionalitat/filtre-pendents | fa 3 setmanes | Bruno Salas | Corregeix el focus del camp després d'afegir una tasca
  funcionalitat/comptador-tasques | fa 3 setmanes | Ana Ferrer | Marca les tasques com a completades en fer clic
  experiment/emmagatzematge-indexeddb | fa 2 mesos | Ana Ferrer | Desa les tasques a IndexedDB
  prova | fa 4 mesos | Ana Ferrer | Afegeix els estils base del llistat

Aquesta sí que és una vista útil. D'un cop d'ull es veu què és viu, qui ho porta i què és l'últim que s'hi va fer.

Els marcadors més pràctics:

Marcador Contingut
%(HEAD) Un * si és la branca actual, un espai si no
%(refname:short) El nom de la branca sense refs/heads/
%(committerdate:relative) «fa 3 setmanes»
%(committerdate:short) 2026-07-10
%(authorname) Autor de l'últim commit
%(contents:subject) Primera línia del missatge
%(objectname:short) Hash abreujat
%(color:...) / %(color:reset) Color

Com que és impossible recordar aquesta línia, es guarda com a àlies:

git config --global alias.branques "branch --sort=-committerdate --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) | %(committerdate:relative) | %(authorname) | %(contents:subject)'"
git branques

Els àlies tenen lliçó pròpia al mòdul 6; aquest és un bon candidat per a la teva col·lecció.

  1. Reanomenar branques amb -m

git branch -m <nom-antic> <nom-nou>

En Bruno va obrir fa uns dies una branca anomenada apany2 i ara ningú no sap què conté. Després de mirar-la, l'Ana li posa un nom que digui alguna cosa:

git branch -m apany2 correccio/focus-despres-esborrar

Si vols reanomenar la branca on ets, n'hi ha prou amb un argument:

git switch funcionalitat/exportar-csv
git branch -m funcionalitat/exportacio-csv

Hi ha una variant majúscula, -M, que força el reanomenament encara que ja existeixi una branca amb el nom de destinació, sobreescrivint-la. La mateixa advertència de sempre: -M pot deixar commits orfes sense avisar. Fes servir -m llevat que sàpigues exactament què fas.

Què fa realment

Res sorprenent, a aquestes altures del mòdul:

ls .git/refs/heads/
cat .git/HEAD

Reanomenar una branca és reanomenar el fitxer de 41 bytes i, si era la branca actual, actualitzar .git/HEAD perquè apunti al nom nou. Els commits no es toquen: són immutables i ni se n'assabenten.

Per això reanomenar és una operació totalment segura en local. Quan la branca ja s'ha compartit amb l'equip la cosa canvia, perquè els altres continuen veient el nom antic; això pertany al mòdul 4.

  1. Esborrar branques: -d davant de -D

git branch -d <branca>     # esborrat SEGUR
git branch -D <branca>     # esborrat FORÇAT

El segur, sobre una branca ja integrada:

git branch -d funcionalitat/comptador-tasques
Deleted branch funcionalitat/comptador-tasques (was 9d1e4b7).

Fixa't que Git et dona el hash d'on era. No és cortesia: és la dada amb què pots recrear la branca si t'has equivocat (git branch <nom> 9d1e4b7). Copia-la si tens el més mínim dubte.

Se'n poden esborrar diverses de cop:

git branch -d funcionalitat/filtre-pendents funcionalitat/ordre-alfabetic neteja/esborrar-notes
Deleted branch funcionalitat/filtre-pendents (was b2e6d3f).
Deleted branch funcionalitat/ordre-alfabetic (was a1e5c93).
Deleted branch neteja/esborrar-notes (was 7f3c9a2).

Què s'esborra exactament

El fitxer de 41 bytes. Res més.

ls .git/refs/heads/funcionalitat/

Els commits continuen íntegres a .git/objects/. L'únic que ha desaparegut és el nom que hi apuntava. Si aquests commits continuen sent assolibles des de main (que és el cas quan la branca estava fusionada), no canvia absolutament res al repositori.

Aquest és el motiu pel qual esborrar una branca fusionada és una operació trivial i sense risc, i pel qual no cal tenir-li cap respecte.

Dues limitacions

No pots esborrar la branca on ets:

git branch -d main
error: Cannot delete branch 'main' checked out at '/home/ana/projectes/gestor-tasques'

I, des de Git 2.5, tampoc no pots esborrar una branca que estigui activa en una altra còpia de treball (git worktree, lliçó 06-06). En tots dos casos la solució és la mateixa: git switch a una altra branca i repetir.

  1. Quan l'esborrat segur falla

git branch -d funcionalitat/exportacio-csv
error: The branch 'funcionalitat/exportacio-csv' is not fully merged.
If you are sure you want to delete it, run 'git branch -D funcionalitat/exportacio-csv'.

Què significa exactament aquest missatge: la punta d'aquesta branca no és assolible des de la branca actual (ni des de la seva branca de seguiment, si en tingués). És a dir, hi ha commits que no són en cap altre lloc del graf.

I què NO significa: no significa que la feina s'hagi perdut, ni que el contingut no sigui a main. Recorda el cas del squash: el contingut de funcionalitat/exportacio-csv és íntegre a main al commit 3b9e7d1, però els seus sis commits originals no. Git raona sobre el graf, no sobre el contingut.

Abans de forçar, comprova. Aquest és el reflex que cal adquirir:

# Quins commits es quedarien sense referència?
git log --oneline main..funcionalitat/exportacio-csv
e9a2c5f Ara sí
7e2a9c4 Treu el console.log
1d6b4f8 wip 2
5a8e2b9 Arregla el separador
9f3a2c1 wip
4a1c7e3 Primer intent d'exportació
# El seu contingut és realment a main?
git diff main funcionalitat/exportacio-csv
(sense sortida)

Sense diferències: el contingut és idèntic. Es va integrar amb squash i no es perd res. Ara sí, amb coneixement de causa:

git branch -D funcionalitat/exportacio-csv
Deleted branch funcionalitat/exportacio-csv (was e9a2c5f).

-D és recuperable (durant un temps)

Un esborrat amb -D no és la fi del món, i convé saber-ho per no viure amb por. Els commits continuen a la base de dades d'objectes, i Git manté un registre anomenat reflog amb tots els moviments de referències. Mentre el hash sigui recuperable —d'aquí que git branch -D l'imprimeixi en esborrar— n'hi ha prou de recrear la branca:

git branch funcionalitat/exportacio-csv e9a2c5f

Els commits sense cap referència acaben sent eliminats pel recollidor d'escombraries (git gc), però no de manera immediata: el termini per defecte és de 30 dies per als objectes inassolibles i 90 dies per a les entrades del reflog. Hi ha marge de sobres.

Tot el procediment de rescat —trobar el hash amb git reflog i git fsck --lost-found quan ja no el tens apuntat— es veu a la lliçó 09-04. Aquí queda't amb la idea tranquil·litzadora: -D gairebé mai no és irreversible.

-d -D
Comprova si està fusionada No
Falla si hi ha commits sense integrar No
Imprimeix el hash en esborrar
Recuperable després Sí (no es perd res) Sí, via reflog, durant setmanes
Quan fer-lo servir Sempre per defecte Quan has comprovat i saps què fas

  1. Convencions de noms

Git no imposa cap estructura als noms de branca més enllà d'uns quants caràcters prohibits. El que fan els equips és adoptar prefixos amb barra que agrupen les branques per propòsit, exactament com hem anat fent al mòdul.

Prefix Per a què Exemple
funcionalitat/ (o feature/) Funcionalitat nova funcionalitat/exportar-csv
correccio/ (o fix/, bugfix/) Correcció d'una fallada correccio/missatge-llista-buida
hotfix/ Correcció urgent sobre la versió en producció hotfix/error-en-desar
experiment/ (o spike/) Prova que pot acabar descartada experiment/emmagatzematge-indexeddb
documentacio/ (o docs/) Només documentació documentacio/guia-installacio
refactor/ Reorganització sense canvi funcional refactor/separar-modul-tasques
neteja/ (o chore/) Manteniment, dependències, configuració neteja/esborrar-notes
release/ Preparació d'una versió release/1.3.0

Molts equips hi afegeixen l'identificador de la tasca del gestor d'incidències, que permet anar de la branca a l'especificació i a l'inrevés:

funcionalitat/GT-142-exportar-csv
correccio/GT-158-missatge-llista-buida

I alguns hi inclouen el nom de qui la porta, útil en equips grans:

ana/funcionalitat/ordre-alfabetic
bruno/correccio/focus-del-camp

L'avantatge pràctic de la barra

No és només estètica. La barra permet filtrar:

git branch --list 'funcionalitat/*'
git branch --list 'correccio/*'

I fa que l'autocompletat sigui utilitzable: escrius git switch fun<TAB> i l'intèrpret d'ordres t'ofereix només aquest grup.

També convé saber per què la barra té un límit: com que els noms es converteixen en rutes dins de .git/refs/heads/, no pot existir alhora una branca anomenada funcionalitat i una altra anomenada funcionalitat/ordre. La primera seria un fitxer i la segona necessitaria que funcionalitat fos un directori. Git ho rebutja:

git branch funcionalitat
fatal: cannot lock ref 'refs/heads/funcionalitat': 'refs/heads/funcionalitat/ordre-alfabetic' exists; cannot create 'refs/heads/funcionalitat'

És un error críptic amb una explicació molt simple, i ara ja la coneixes.

Regles d'estil que ajuden

  • Minúscules i guionets: funcionalitat/exportar-csv, no Funcionalitat/ExportarCSV. Evita sorpreses entre sistemes de fitxers sensibles i no sensibles a majúscules (recorda que l'Ana és a Ubuntu, en Bruno a macOS i la Carla a Windows).
  • Sense accents ni ç. correccio/, no correcció/. Git els admet, però acaben en URL, en noms de fitxer i en sortides d'eines de tercers on donen problemes.
  • Descriptiu però curt: correccio/focus-despres-afegir, no correccio/arreglar-el-problema-del-focus-que-va-reportar-el-client-el-dimarts.
  • Res de prova, temporal, nova, apany2. D'aquí a dues setmanes no sabràs què eren, i per això ningú no s'atrevirà a esborrar-les.

Els fluxos de treball amb nom

Existeixen metodologies completes que defineixen quines branques hi ha, com es diuen, d'on surten i on s'integren. Les més conegudes:

  • Git Flow: branques develop, release/*, hotfix/* i feature/* sobre una main que només conté versions publicades.
  • GitHub Flow: una sola branca de llarga durada (main) i branques de treball de vida curta que s'integren mitjançant propostes de canvi.
  • Trunk Based Development: tothom integra al tronc diàriament, amb branques d'hores i no de dies.

Cadascuna té els seus supòsits sobre la mida de l'equip, la freqüència de publicació i el nivell d'automatització. Les estudiarem al mòdul 7, on ja tindrem els remots i les propostes de canvi per entendre-les de debò. Per ara, l'important: la convenció concreta importa menys que el fet que tot l'equip segueixi la mateixa.

  1. Quins noms admet Git: git check-ref-format

Les regles estan definides formalment i es poden comprovar:

git check-ref-format --branch 'funcionalitat/exportar-csv'
funcionalitat/exportar-csv

Si el nom és vàlid, l'imprimeix i retorna 0. Si no:

git check-ref-format --branch 'funcionalitat/exportar csv'
fatal: 'funcionalitat/exportar csv' is not a valid branch name

Les regles principals, amb la raó de cadascuna:

Prohibit Exemple no vàlid Per què
Espais i caràcters de control la meva branca Trenquen l'ús a la línia d'ordres
Dos punts seguits .. branca..vella .. és l'operador de rangs
Els caràcters ~ ^ : ? * [ \ branca^2, branca:x Són sintaxi de referències o comodins
Començar o acabar en /, o // /branca, branca//x No són rutes vàlides
Acabar en . o en .lock branca., branca.lock .lock és el mecanisme de bloqueig de Git
El component @{ branca@{1} És la sintaxi del reflog
Un sol @ @ És un àlies de HEAD
Començar un component per . .oculta Seria un fitxer ocult

Un detall curiós i coherent amb tot el que has après: la majoria d'aquestes regles existeixen perquè el nom de la branca és alhora una ruta de fitxer i una expressió que Git ha de poder analitzar. Prohibir ^ no és un caprici: si existís una branca anomenada meva^branca, git log meva^branca seria ambigu.

Comprovació en un script:

NOM="funcionalitat/cosa-nova"
if git check-ref-format --branch "$NOM" > /dev/null 2>&1; then
  git switch -c "$NOM"
else
  echo "Nom de branca no vàlid: $NOM"
fi

Aquesta mena de validació és exactament el que s'automatitza amb un hook per impedir que entrin noms que no segueixen la convenció de l'equip. Els hooks són el tema de la lliçó 06-01.

  1. Higiene: detectar branques obsoletes

Reunim-ho tot en una rutina de manteniment. N'hi ha prou de fer-la un cop al mes.

Pas 1: veure el panorama ordenat per antiguitat.

git branch --sort=committerdate --format='%(committerdate:short) %(refname:short) %(authorname)'
2026-03-12 prova Ana Ferrer
2026-05-28 experiment/emmagatzematge-indexeddb Ana Ferrer
2026-07-10 funcionalitat/comptador-tasques Ana Ferrer
2026-07-12 funcionalitat/filtre-pendents Bruno Salas
...

Sense el guionet, l'ordre és ascendent: el més vell a dalt, que és el que vols quan busques candidates a esborrar.

Pas 2: separar les integrades de les que no ho estan.

echo "=== Fusionades a main (es poden esborrar) ==="
git branch --merged main | grep -v ' main$'

echo "=== Sense fusionar (revisar abans) ==="
git branch --no-merged main

Pas 3: revisar una per una les que no estan fusionades. Per a cadascuna:

BRANCA=experiment/emmagatzematge-indexeddb

# Quins commits té que main no tingui?
git log --oneline main..$BRANCA

# Quant fa de l'últim?
git log -1 --format='%ar per %an' $BRANCA

# El seu contingut és a main d'una altra manera (squash)?
git diff main..$BRANCA --stat

Amb aquestes tres dades, la decisió és fàcil: si el contingut ja és a main, -D sense por; si té feina real i recent, es deixa; si té feina real però de fa mesos, es parla amb qui la va obrir abans de tocar res.

Pas 4: esborrar les integrades.

git branch --merged main | grep -v '^\*' | grep -v ' main$' | xargs -r git branch -d

Senyals d'una branca obsoleta

Senyal Què sol indicar
Fusionada a main Va complir la seva funció; esborrar
Sense commits en més d'un mes Feina abandonada; preguntar
Nom genèric (prova, temp, nova) Ningú no recorda per a què era
El seu contingut ja és a main sense estar fusionada Es va integrar amb squash; esborrar amb -D
Centenars de commits per darrere de main Fusionar-la serà un infern; replantejar

I una reflexió de fons

La millor gestió de branques és no necessitar-la: si les branques viuen dos o tres dies i s'esborren en integrar-les, el repositori no acumula mai brossa. La neteja mensual és un pedaç per a un problema que s'evita treballant amb branques curtes.

És la mateixa conclusió a què vam arribar amb els conflictes a la lliçó anterior, i no és casualitat: la vida curta de les branques resol alhora la divergència, els conflictes i el desordre. És la idea que sosté el desenvolupament basat en tronc i bona part del mòdul 7.

  1. Tancament del mòdul

Recapitulem el que hem construït en aquestes sis lliçons.

Vam començar amb una promesa del mòdul 2 —«una branca és un fitxer amb un hash a dins»— i la vam complir fins al byte: 41, exactament. Vam veure que HEAD és un altre fitxer que apunta a una branca, no a un commit, i que aquesta indirecció és el que permet que confirmar mogui el punter correcte. Vam entendre per què les branques de Git són gratis davant de les de Subversion, i què significa que dues branques divergeixin des d'un ancestre comú.

Després les vam crear i ens vam moure entre elles amb git branch, git switch i git switch -c, vam entendre per què Git va separar checkout en dues ordres, què passa amb els canvis sense confirmar en canviar de branca i què és el HEAD desacoblat.

Les vam tornar a ajuntar amb git merge, distingint el fast-forward —un punter que avança— de la fusió a tres bandes que crea un commit amb dos pares, i vam aprendre a forçar o prohibir cada comportament amb --no-ff i --ff-only. Vam estudiar les estratègies (ort, resolve, octopus, ours, subtree), les opcions -X, la diferència crítica entre -s ours i -X ours, i el squash merge.

Vam resoldre un conflicte de debò: els marcadors, l'estil zdiff3 que mostra l'ancestre, les tres etapes de l'índex, git add com a manera de dir «resolt» i git merge --abort com a tecla d'escapament.

I hem acabat posant-hi ordre: llistar, filtrar, reanomenar, esborrar amb criteri i anomenar bé.

El problema que queda obert

I tanmateix, tot el que hem fet en aquest mòdul ha passat dins d'un únic portàtil. Totes les branques viuen al .git/ de l'Ana. Quan dèiem «en Bruno va obrir una branca», en realitat raonàvem com si la seva feina ja fos allà.

Al món real no hi és. L'Ana treballa a Ubuntu, en Bruno a macOS, i els seus repositoris són dues bases de dades d'objectes completament independents que no es coneixen entre si. Els commits d'en Bruno són al seu MacBook i els de l'Ana al seu Ubuntu, i cap git merge del món pot fusionar una cosa que no és al teu propi .git/objects/.

Falten les respostes a preguntes molt concretes:

  • Com arriben els objectes d'un repositori a un altre?
  • On viu la còpia «oficial» del projecte?
  • Què és exactament aquell origin/main que va aparèixer fugaçment a la lliçó 02-06, i per què porta una barra al nom?
  • Com s'autentica en Bruno per poder enviar la seva feina?
  • Què passa si dues persones envien canvis sobre la mateixa branca alhora?
  • I sobretot: la Carla encara no s'ha incorporat. Està esperant al seu Windows 11 que li diguin d'on descarregar el projecte.

Al mòdul 4: Treballant amb Repositoris Remots tanquem aquest cercle. Veurem què és un remot i per què no és més que un nom curt per a una URL, com es registra amb git remote add, com funciona l'autenticació amb SSH i amb tokens, la diferència crucial entre git fetch i git pull, com enviar la feina amb git push, i què són les branques de seguiment que fan que git status et digui «la teva branca està 3 commits per davant d'origin/main».

I la bona notícia és que tot el que has après en aquest mòdul continua sent cert sense cap canvi. Fusionar la feina d'una altra persona és exactament el mateix git merge que has fet servir aquí. Els conflictes es resolen igual. Les estratègies són les mateixes. L'únic que s'hi afegeix és el transport: com aconsegueixen els objectes viatjar d'un .git/ a un altre. Un cop han arribat, tot funciona com ja saps.

Errors Habituals i Consells

Error 1: interpretar --no-merged com «aquí hi ha feina perduda». Només significa que la punta d'aquesta branca no és assolible des d'on ets. Una branca integrada amb squash sempre hi apareixerà encara que el seu contingut sigui íntegre a main. Comprova amb git diff main..<branca> abans de treure conclusions.

Error 2: fer servir -D per costum perquè -d «dona la llauna». Aquesta llauna és la xarxa de seguretat. Cada vegada que -d falla, t'està dient alguna cosa que mereix trenta segons de comprovació. Reserva -D per a després d'haver mirat.

Error 3: no apuntar el hash que imprimeix l'esborrat. Deleted branch X (was 9d1e4b7) és el teu bitllet de tornada. Si t'adones al minut següent que t'has equivocat, git branch X 9d1e4b7 ho arregla. Sense el hash, cal anar al reflog.

Error 4: crear una branca amb el nom d'un directori de branques existent. Si tens funcionalitat/ordre-alfabetic, no pots crear funcionalitat. L'error que dona Git és críptic, però la causa és que els noms són rutes de fitxer.

Error 5: acumular branques «per si de cas». El cost no és l'espai (són 41 bytes) sinó la confusió: ningú no sap quines són vives, l'autocompletat es torna inútil i les llistes deixen de llegir-se. Si la branca està fusionada, esborra-la; els commits no aniran enlloc.

Consell 1: guarda el llistat bonic com a àlies. git branques amb data relativa, autor i últim missatge és la vista que de debò faràs servir. La línia completa és a l'apartat 3.

Consell 2: fes la neteja mensual, i fes-la en dos passos. Primer llistar, revisar amb els ulls, i després esborrar. Mai en una sola ordre encadenada sense mirar.

Consell 3: anomena les branques pensant en qui les vegi d'aquí a un mes. Inclou el prefix de tipus i, si l'equip fa servir un gestor d'incidències, el seu identificador. És la diferència entre una llista de branques que s'entén i una que fa por tocar.

Consell 4: esborra la branca tan bon punt la integris. Convertir-ho en l'últim pas del ritual de fusió —fusionar, comprovar, esborrar— fa que la neteja mensual no arribi mai a ser necessària.

Exercicis

Exercici 1: auditoria d'un repositori

En un repositori amb diverses branques (crea-les si cal), respon amb ordres:

  1. Quines branques es poden esborrar ara mateix sense perdre cap commit?
  2. Quines branques tenen feina sense integrar i quants commits són en cada cas?
  3. Quina és la branca que porta més temps sense activitat?
  4. A quines branques és present un commit concret?

Exercici 2: el cas del squash

Reprodueix la situació que confon --merged: integra una branca amb --squash i demostra amb ordres que:

  1. El seu contingut és a main.
  2. Git la considera no fusionada.
  3. -d es nega a esborrar-la i -D no.
  4. Després d'esborrar-la amb -D, es pot recrear exactament on era.

Exercici 3: validar noms de branca

Escriu un petit script que rebi un nom de branca i decideixi si és vàlid segons Git i segons una convenció d'equip que exigeixi un d'aquests prefixos: funcionalitat/, correccio/, hotfix/ o documentacio/. Prova'l amb almenys quatre noms, vàlids i no vàlids.

Solucions

Solució 1:

# 1. Branques esborrables sense perdre res
git branch --merged main | grep -v ' main$'
  correccio/missatge-llista-buida
  funcionalitat/comptador-tasques
  prova

La seva punta és assolible des de main: esborrar-les no deixa cap commit sense referència.

# 2. Branques amb feina sense integrar, amb el recompte
for b in $(git branch --no-merged main --format='%(refname:short)'); do
  n=$(git rev-list --count main..$b)
  echo "$b: $n commits sense integrar"
done
documentacio/actualitzar-notes: 1 commits sense integrar
funcionalitat/exportacio-csv: 6 commits sense integrar

git rev-list --count main..<branca> compta els commits del rang, amb la mateixa semàntica que vas aprendre a la lliçó 02-06.

# 3. La branca més inactiva: ordre ascendent, primera línia
git branch --sort=committerdate --format='%(committerdate:short) %(refname:short)' | head -1
2026-03-12 prova
# 4. A quines branques és un commit
git branch --contains 6d3f8b2
  correccio/missatge-llista-buida
* main

Solució 2:

mkdir /tmp/practica-gestio && cd /tmp/practica-gestio
git init -b main
echo "base" > f.txt && git add . && git commit -m "Base"

git switch -c funcionalitat/alguna-cosa
echo "pas 1" >> f.txt && git commit -am "Pas 1"
echo "pas 2" >> f.txt && git commit -am "Pas 2"
echo "pas 3" >> f.txt && git commit -am "Pas 3"

git switch main
git merge --squash funcionalitat/alguna-cosa
git commit -m "Afegeix la funcionalitat completa"
# 1. El contingut SÍ que és a main
git diff main funcionalitat/alguna-cosa
(sense sortida)

Zero diferències: els fitxers són idèntics.

# 2. Però Git no la considera fusionada
git branch --merged main
* main
git branch --no-merged main
  funcionalitat/alguna-cosa
git log --oneline main..funcionalitat/alguna-cosa
5f8b2e1 Pas 3
2c9d4e6 Pas 2
9f4c2a8 Pas 1

Tres commits que main no té, encara que el seu efecte sí que hi sigui, condensat en un únic commit diferent.

# 3. L'esborrat segur falla
git branch -d funcionalitat/alguna-cosa
error: The branch 'funcionalitat/alguna-cosa' is not fully merged.
If you are sure you want to delete it, run 'git branch -D funcionalitat/alguna-cosa'.
git branch -D funcionalitat/alguna-cosa
Deleted branch funcionalitat/alguna-cosa (was 5f8b2e1).
# 4. Recreació exacta amb el hash que Git ens va donar
git branch funcionalitat/alguna-cosa 5f8b2e1
git log --oneline -1 funcionalitat/alguna-cosa
5f8b2e1 Pas 3

Idèntica a com era. Els commits no se'n van anar mai: només es va esborrar el nom que els assenyalava.

Solució 3:

#!/bin/bash
# validar-branca.sh — comprova nom vàlid per a Git i per a l'equip

NOM="$1"

if [ -z "$NOM" ]; then
  echo "Ús: $0 <nom-de-branca>"
  exit 2
fi

# 1. L'accepta Git?
if ! git check-ref-format --branch "$NOM" > /dev/null 2>&1; then
  echo "REBUTJAT: '$NOM' no és un nom de branca vàlid per a Git."
  exit 1
fi

# 2. Compleix la convenció de l'equip?
case "$NOM" in
  funcionalitat/*|correccio/*|hotfix/*|documentacio/*)
    ;;
  *)
    echo "REBUTJAT: '$NOM' ha de començar per funcionalitat/, correccio/, hotfix/ o documentacio/."
    exit 1
    ;;
esac

# 3. Regla d'estil addicional: sense majúscules
if echo "$NOM" | grep -q '[A-ZÀÈÉÍÒÓÚÇ]'; then
  echo "REBUTJAT: '$NOM' no ha de portar majúscules ni caràcters accentuats."
  exit 1
fi

echo "ACCEPTAT: $NOM"
exit 0

Proves:

chmod +x validar-branca.sh

./validar-branca.sh 'funcionalitat/exportar-csv'
./validar-branca.sh 'correccio/missatge-llista-buida'
./validar-branca.sh 'apany2'
./validar-branca.sh 'funcionalitat/Exportar CSV'
./validar-branca.sh 'correccio/branca..vella'
ACCEPTAT: funcionalitat/exportar-csv
ACCEPTAT: correccio/missatge-llista-buida
REBUTJAT: 'apany2' ha de començar per funcionalitat/, correccio/, hotfix/ o documentacio/.
REBUTJAT: 'funcionalitat/Exportar CSV' no és un nom de branca vàlid per a Git.
REBUTJAT: 'correccio/branca..vella' no és un nom de branca vàlid per a Git.

Fixa't en el quart cas: l'espai fa que el rebutgi ja git check-ref-format, sense que arribem a la comprovació de majúscules. I el cinquè el rebutja pels .., que Git reserva per als rangs de commits.

Aquest script és exactament el que es converteix en un hook pre-commit o pre-push perquè la convenció s'apliqui sola, sense dependre de la disciplina de cada persona. Ho veurem a la lliçó 06-01.

Conclusió

Amb aquesta lliçó tanquem el mòdul 3. El que hem après aquí:

  • git branch -v mostra la punta i l'últim missatge de cada branca; -vv hi afegirà la informació de seguiment quan tinguem remots (mòdul 4).
  • --merged i --no-merged responen a la pregunta clau del manteniment: quines branques es poden esborrar sense perdre cap commit. Compte amb les integrades mitjançant squash, que sempre apareixen com a no fusionades encara que el seu contingut sigui a main.
  • --sort=-committerdate amb --format converteix un llistat alfabètic inútil en una vista real de què és viu, qui ho porta i des de quan. Guarda-ho com a àlies.
  • git branch -m reanomena: és reanomenar el fitxer de 41 bytes i, si era la branca actual, actualitzar HEAD. Totalment segur en local.
  • -d davant de -D: el primer comprova que no es perd res i es nega si no és així; el segon força. Quan -d falla, significa que la punta no és assolible des d'on ets, no necessàriament que la feina es perdi. Comprova amb git log main..<branca> i git diff main <branca> abans de forçar. -D és recuperable durant setmanes gràcies al reflog (mòdul 9).
  • Esborrar una branca esborra 41 bytes. Els commits continuen intactes a la base de dades d'objectes.
  • Les convencions de noms (funcionalitat/, correccio/, hotfix/…) agrupen, permeten filtrar i fan útil l'autocompletat. Les regles formals de Git es comproven amb git check-ref-format --branch.
  • La higiene és una rutina de quatre passos: llistar per antiguitat, separar fusionades de no fusionades, revisar les segones i esborrar les primeres. I la millor higiene és tenir branques de vida curta que no arribin a acumular-se.

El que ve

Ja domines les branques: què són, com crear-les, com fusionar-les, com resoldre els xocs i com mantenir el repositori ordenat. Però tot això dins d'un únic .git/.

Al mòdul 4: Treballant amb Repositoris Remots el projecte surt per fi del portàtil de l'Ana. Veurem què és un remot, com es registra, com s'autentica l'accés, la diferència entre git fetch i git pull, com enviar la feina amb git push i què són les branques de seguiment. I la Carla s'incorporarà per fi a l'equip des del seu Windows 11, clonant el projecte tal com va fer en Bruno a la lliçó 02-02, però aquesta vegada amb un repositori que ja té història, branques i una manera de treballar.

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