A la lliçó anterior vam desmuntar el misteri: una branca és un fitxer de 41 bytes amb un hash a dins, i HEAD és un altre fitxer que diu en quina branca ets. Ara farem servir aquesta maquinària. L'Ana obrirà per fi funcionalitat/comptador-tasques, en Bruno farà el mateix amb funcionalitat/filtre-pendents, i el repositori deixarà de tenir una sola línia de treball.

Crear branques en Git és trivial —ho veuràs en un segon—, però moure's entre elles té matisos que convé dominar des del principi: què passa amb la feina que tens a mitges, per què de vegades Git et deixa canviar de branca i d'altres s'hi nega, i què és aquell estat de HEAD desacoblat que apareix quan menys t'ho esperes i que espanta tothom la primera vegada.

També aclarirem un dubte que arrossega qualsevol que aprengués Git abans del 2019: la diferència entre git checkout i git switch, i per què Git va decidir partir una ordre en dues.

Contingut

  1. git branch: crear sense moure's
  2. git switch: moure's
  3. git switch -c: crear i moure's en un pas
  4. git switch davant de git checkout
  5. Crear una branca des d'un punt concret de l'historial
  6. git switch -: alternar entre dues branques
  7. Canvis sense confirmar en canviar de branca
  8. HEAD desacoblat (detached HEAD)
  9. El repositori de l'equip, ja amb branques

  1. git branch: crear sense moure's

L'Ana és a main, amb el repositori tal com el vam deixar:

git log --oneline
c5d9b1e (HEAD -> main) Documenta la instal·lació al README
4e7f2a9 Afegeix l'esborrat de tasques al llistat
8b6d3c2 Afegeix els estils base del llistat
1a4c8d6 Estructura inicial del gestor de tasques

Vol una branca per al comptador de tasques:

git branch funcionalitat/comptador-tasques
(sense sortida)

Silenci absolut. En Git, el silenci sol voler dir èxit. Vegem què ha passat exactament:

ls .git/refs/heads/
funcionalitat  main
cat .git/refs/heads/funcionalitat/comptador-tasques
c5d9b1e7a3f2d8b4e6c1a9f5d3b7e2c8a4f6d1b9

Un fitxer nou, amb el hash del commit on era l'Ana. (Nota lateral interessant: com que el nom de la branca porta una barra, Git ha creat un directori funcionalitat/ dins de refs/heads/. Els noms de branca amb barres són simplement rutes de fitxer; tornarem sobre les convencions de noms a la lliçó 03-06.)

Ara la part important:

cat .git/HEAD
ref: refs/heads/main

HEAD no s'ha mogut. L'Ana continua a main. Ha creat un punter nou, però no s'hi ha situat:

git status
On branch main
nothing to commit, working tree clean
git branch
  funcionalitat/comptador-tasques
* main

L'asterisc marca la branca actual. Hi ha dues branques i totes dues apunten al mateix commit.

gitGraph
   commit id: "1a4c8d6"
   commit id: "8b6d3c2"
   commit id: "4e7f2a9"
   commit id: "c5d9b1e"
   branch comptador-tasques

Regla: git branch <nom> crea el punter i no toca res més. Ni HEAD, ni el directori de treball, ni l'àrea de preparació.

Si l'Ana confirmés ara, el commit aniria a main, perquè és on continua apuntant HEAD. És un error clàssic: crear la branca i oblidar-se de canviar-s'hi. Per això, a la pràctica, gairebé mai no es fa servir git branch a seques per començar a treballar; es fa servir la variant de l'apartat 3.

  1. git switch: moure's

Per situar-se a la branca acabada de crear:

git switch funcionalitat/comptador-tasques
Switched to branch 'funcionalitat/comptador-tasques'

I ara sí:

cat .git/HEAD
ref: refs/heads/funcionalitat/comptador-tasques

Això és tot el que ha fet Git en aquest cas: reescriure el fitxer .git/HEAD. Com que les dues branques apuntaven al mateix commit, el directori de treball no ha canviat ni un byte.

git status
On branch funcionalitat/comptador-tasques
nothing to commit, working tree clean

Quan les branques apunten a commits diferents, git switch fa alguna cosa més: a banda de reescriure HEAD, actualitza el directori de treball i l'àrea de preparació perquè reflecteixin l'arbre del commit de destinació. És a dir, canvia els fitxers del teu disc. Això és el que passa en les tres operacions internes d'un canvi de branca:

Pas Què fa Git
1 Comprova que el canvi és segur (vegeu l'apartat 7)
2 Actualitza el directori de treball i l'índex a l'arbre del commit de destinació
3 Reescriu .git/HEAD amb la branca nova

L'Ana escriu el comptador de tasques a app.js i confirma:

git add app.js
git commit -m "Afegeix el comptador de tasques pendents"
[funcionalitat/comptador-tasques 6f2b9d4] Afegeix el comptador de tasques pendents
 1 file changed, 12 insertions(+)

Fixa't en el nom entre claudàtors: [funcionalitat/comptador-tasques 6f2b9d4]. Git t'està dient en quina branca ha caigut el commit. És una comprovació gratuïta que convé llegir sempre.

L'Ana afegeix després el marcatge de completades:

git commit -am "Marca les tasques com a completades en fer clic"
[funcionalitat/comptador-tasques 9d1e4b7] Marca les tasques com a completades en fer clic
 2 files changed, 18 insertions(+), 2 deletions(-)

Estat actual:

git log --oneline --graph --all
* 9d1e4b7 (HEAD -> funcionalitat/comptador-tasques) Marca les tasques com a completades en fer clic
* 6f2b9d4 Afegeix el comptador de tasques pendents
* c5d9b1e (main) Documenta la instal·lació al README
* 4e7f2a9 Afegeix l'esborrat de tasques al llistat
* 8b6d3c2 Afegeix els estils base del llistat
* 1a4c8d6 Estructura inicial del gestor de tasques

main s'ha quedat quieta a c5d9b1e, exactament com era. La feina de l'Ana està aïllada: pot confirmar tant com vulgui sense tocar la línia principal del projecte.

  1. git switch -c: crear i moure's en un pas

Crear una branca i no canviar-s'hi és estrany. Per això existeix la drecera:

git switch -c funcionalitat/filtre-pendents
Switched to a new branch 'funcionalitat/filtre-pendents'

La -c ve de create. És exactament equivalent a:

git branch funcionalitat/filtre-pendents
git switch funcionalitat/filtre-pendents

Aquesta és la forma que faràs servir el 95 % de les vegades. git branch <nom> a seques queda reservat per als casos en què vols marcar un punt de l'historial sense abandonar el que estàs fent (per exemple, deixar un marcador abans d'una operació arriscada).

Un detall important que sovint es passa per alt: la branca nova es crea des d'on ets ara. Si l'Ana executés aquella ordre estant a funcionalitat/comptador-tasques, la branca nova partiria de 9d1e4b7 i arrossegaria el comptador de tasques, que no és el que vol. Per a la feina d'en Bruno, el punt de partida correcte és main:

git switch main
git switch -c funcionalitat/filtre-pendents

O, encara millor, indicant-ho explícitament en una sola ordre —la forma que veurem a l'apartat 5.

Hi ha una variant majúscula, -C, que crea la branca o la reinicia si ja existeix:

git switch -C funcionalitat/filtre-pendents

Fes-la servir amb cura: si la branca ja existia apuntant a un altre lloc, -C mou el punter sense preguntar i pots deixar commits orfes. -c, en canvi, falla amb fatal: a branch named '…' already exists, que gairebé sempre és el que vols.

  1. git switch davant de git checkout

Si has vist Git en qualsevol tutorial anterior al 2019, o en la majoria dels que hi ha per internet avui, hauràs vist això:

git checkout funcionalitat/comptador-tasques      # equival a git switch
git checkout -b funcionalitat/filtre-pendents     # equival a git switch -c

Funciona. git checkout no està obsolet ni desapareixerà. Però des de Git 2.23 (agost del 2019) existeixen git switch i git restore, i per a feina nova són l'opció recomanada. La raó és senzilla: git checkout feia massa coses diferents.

Necessitat Ordre antiga Ordre moderna
Canviar de branca git checkout <branca> git switch <branca>
Crear branca i canviar-s'hi git checkout -b <branca> git switch -c <branca>
Crear branca des d'un commit git checkout -b <branca> <commit> git switch -c <branca> <commit>
Anar a un commit solt git checkout <commit> git switch --detach <commit>
Tornar a la branca anterior git checkout - git switch -
Descartar canvis d'un fitxer git checkout -- <fitxer> git restore <fitxer>
Treure de l'àrea de preparació git reset HEAD <fitxer> git restore --staged <fitxer>
Recuperar un fitxer d'un altre commit git checkout <commit> -- <fitxer> git restore --source=<commit> <fitxer>

Mira les tres últimes files, que són les importants. git checkout servia tant per navegar entre branques (una operació innòcua i reversible) com per destruir canvis del directori de treball (una operació irreversible). El mateix verb per a dues coses de risc oposat.

I el desastre potencial era a l'ambigüitat. Imagina que existeix un fitxer anomenat informe i també una branca anomenada informe:

git checkout informe

Canvia de branca o descarta els canvis del fitxer? Git resolia a favor de la branca i calia escriure git checkout -- informe (amb el doble guionet separador) per forçar la interpretació de fitxer. Si t'oblidaves del --, podies perdre feina sense avís.

La separació a Git 2.23 elimina l'ambigüitat d'arrel:

  • git switch només treballa amb branques. No pot tocar fitxers.
  • git restore només treballa amb fitxers. No pot canviar de branca.

Ja vas fer servir git restore a la lliçó 02-04, així que ja coneixes la meitat de la reforma. Aquesta lliçó et dona l'altra meitat.

Què fer a la pràctica:

  • Escriu git switch i git restore en la teva feina diària.
  • Aprèn a llegir git checkout, perquè el veuràs a tot arreu: documentació antiga, respostes de Stack Overflow, scripts d'integració contínua i companys amb costums arrelats.
  • No converteixis els scripts existents que funcionen només per moda; checkout continua sent perfectament vàlid.

  1. Crear una branca des d'un punt concret de l'historial

Per defecte, una branca nova parteix de HEAD. Però li pots indicar un altre punt de partida com a segon argument, i això val per a les dues formes de l'ordre:

git branch <nom> <punt-de-partida>
git switch -c <nom> <punt-de-partida>

El punt de partida pot ser qualsevol cosa que Git sàpiga resoldre a un commit, amb tota la sintaxi que vas aprendre a la lliçó 02-06:

# Des d'una altra branca, sense haver de canviar-t'hi primer
git switch -c funcionalitat/filtre-pendents main

# Des d'un commit concret pel seu hash
git switch -c experiment/redisseny 8b6d3c2

# Des d'una posició relativa
git switch -c correccio/regressio HEAD~2

# Des del pare d'un commit concret
git switch -c prova 4e7f2a9^

El primer és el cas d'en Bruno i és la manera correcta de fer-ho: crea la branca a partir de main sense necessitat de canviar-se a main abans. Una ordre en lloc de dues, i sense risc d'oblidar-se'n.

Un cas real on això salva la tarda: has estat programant durant mitja hora a main per despistament, has fet tres commits, i t'adones que haurien d'haver anat en una branca. Solució:

# 1. Crear la branca aquí mateix, amb els tres commits a dins
git branch funcionalitat/el-que-sigui

# 2. Tornar main on havia de ser
git switch main
git reset --hard HEAD~3

# 3. Anar a la branca, on hi ha tota la feina intacta
git switch funcionalitat/el-que-sigui

Fixa't que el pas 1 fa servir git branch sense canviar-se: crea el marcador abans de moure res. (git reset --hard és potent i perillós; l'estudiarem a fons a la lliçó 09-02. Aquí és segur perquè els commits continuen assolibles des de la branca nova.)

  1. git switch -: alternar entre dues branques

Quan estàs revisant la feina d'un company i saltes contínuament entre dues branques, escriure el nom sencer cansa. El guionet sol significa «la branca anterior»:

git switch funcionalitat/comptador-tasques
Switched to branch 'funcionalitat/comptador-tasques'
git switch -
Switched to branch 'funcionalitat/filtre-pendents'
git switch -
Switched to branch 'funcionalitat/comptador-tasques'

És el mateix concepte que cd - a la shell. Funciona amb noms de branca tan llargs com funcionalitat/exportar-llistat-a-csv i estalvia moltíssimes pulsacions.

Per sota, el guionet és un àlies d'@{-1}, que significa «la branca on era fa un canvi». I n'hi ha més:

git switch @{-2}    # la branca on era fa dos canvis

Aquesta informació surt del reflog, el registre que Git manté de tots els moviments de HEAD. És la mateixa eina que permet recuperar feina aparentment perduda, i l'estudiarem a la lliçó 09-04.

  1. Canvis sense confirmar en canviar de branca

Aquí hi ha el matís que més confusió genera. Què passa amb el que tens a mitges quan canvies de branca?

La resposta curta: Git intenta emportar-s'ho amb tu, i si no pot fer-ho sense perdre res, s'hi nega.

La resposta llarga depèn de si els canvis afecten fitxers que difereixen entre les dues branques.

Cas A: Git et deixa passar i s'emporta els canvis

L'Ana és a funcionalitat/comptador-tasques i ha començat a retocar README.md, un fitxer que és idèntic a les dues branques:

git status --short
 M README.md
git switch main
M	README.md
Switched to branch 'main'

Ha funcionat, i aquella línia M README.md és Git avisant-te: «aquell fitxer venia modificat i continua modificat». El canvi ha viatjat amb l'Ana a l'altra branca. Continua sense confirmar, al seu directori de treball:

git status --short
 M README.md

Això és útil a propòsit: et permet començar a escriure alguna cosa, adonar-te que ets a la branca equivocada i corregir-ho sense perdre res.

Cas B: Git s'hi nega

Ara l'Ana és a main i modifica app.js, que sí que difereix entre main i la branca del comptador (el comptador el va canviar allà):

git status --short
 M app.js
git switch funcionalitat/comptador-tasques
error: Your local changes to the following files would be overwritten by checkout:
	app.js
Please commit your changes or stash them before you switch branches.
Aborting

Git s'hi ha negat, i ha fet bé. Per situar-se a l'altra branca hauria de sobreescriure app.js amb la versió d'allà, i això destruiria els canvis de l'Ana sense possibilitat de recuperar-los, perquè mai no han estat a la base de dades d'objectes.

L'important és que l'operació s'ha avortat del tot. Continues on eres i els teus canvis són intactes.

La regla, resumida

Situació Comportament
El fitxer modificat és igual a les dues branques Canvia de branca i s'emporta les modificacions
El fitxer modificat difereix entre les dues branques Rebutja el canvi de branca i avorta
Hi ha canvis a l'àrea de preparació sobre fitxers que no difereixen Canvia de branca i conserva l'àrea de preparació
Hi ha fitxers nous sense seguiment que no existeixen a la destinació Canvia de branca i els deixa on són
Hi ha fitxers sense seguiment que existeixen a la destinació Rebutja, per no sobreescriure'ls

Les tres sortides quan Git s'hi nega

  1. Confirmar. Si la feina té sentit a la branca actual, confirma-la. Si està a mitges, pots fer un commit provisional i arreglar-ho després amb git commit --amend (lliçó 02-04) o amb el rebase interactiu (lliçó 05-02).

  2. Descartar. Si el canvi no val res, git restore app.js l'elimina i el canvi de branca passa a estar permès.

  3. Desar-ho temporalment. Per al cas real —feina a mitges que vols conservar però que encara no mereix un commit— Git té una eina específica: git stash, que aparta els canvis a un magatzem temporal, deixa el directori net i permet recuperar-los després amb git stash pop:

git stash                                  # aparta els canvis
git switch funcionalitat/comptador-tasques # ara sí que pot
# … el que fos a fer …
git switch main
git stash pop                              # recupera els canvis

És una ordre amb bastanta més profunditat de la que suggereix aquest exemple (diverses entrades apilades, incloure fitxers sense seguiment, aplicar en una altra branca…). L'estudiarem sencera a la lliçó 05-04; de moment queda't amb que existeix i amb que és la resposta estàndard a aquest problema.

Forçar el canvi de branca (amb compte)

Existeix l'opció de descartar els canvis i canviar de branca igualment:

git switch --discard-changes funcionalitat/comptador-tasques

(L'equivalent antic era git checkout -f.) És destructiu i irreversible: els canvis no confirmats no són a cap objecte de Git, així que no hi ha cap reflog ni cap recuperació possible. Fes-ho servir només quan estiguis absolutament segur que vols llençar aquella feina.

  1. HEAD desacoblat (detached HEAD)

Recorda la lliçó anterior: HEAD normalment conté ref: refs/heads/<branca>. Però pot contenir directament un hash. Aquest estat s'anomena HEAD desacoblat.

Com s'hi arriba

La forma deliberada és demanar-ho:

git switch --detach 4e7f2a9
Note: switching to '4e7f2a9'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

HEAD is now at 4e7f2a9 Afegeix l'esborrat de tasques al llistat

Git et deixa anar un discurs perquè l'estat és inusual, no perquè sigui perillós. De fet aquell text ja explica gairebé tot el que necessites saber.

Les formes accidentals d'arribar-hi, que són les que espanten:

  • git checkout <hash> (sense -b), la més freqüent amb l'ordre antiga.
  • git checkout v1.2.0, en situar-se en una etiqueta —les etiquetes apunten a commits, no són branques.
  • Durant un git rebase o un git bisect, que treballen internament en aquest estat (mòduls 5 i 6).
  • En situar-se a origin/main en lloc de a main, un error molt comú que veurem al mòdul 4.

Què es veu

cat .git/HEAD
4e7f2a9c8b1d5e3f7a2c9d4b6e8f1a3c5d7b9e2f

Un hash directament, sense ref:. HEAD apunta al commit, no a una branca.

git status
HEAD detached at 4e7f2a9
nothing to commit, working tree clean
git branch
* (HEAD detached at 4e7f2a9)
  funcionalitat/comptador-tasques
  funcionalitat/filtre-pendents
  main

El directori de treball conté els fitxers tal com eren en aquell commit. És un estat perfectament legítim: pots compilar, executar les proves, mirar el codi antic o fins i tot confirmar.

Per a què serveix de debò

No és un accident que calgui evitar; és una eina:

  • Revisar com era el projecte en un moment donat. L'Ana vol veure l'aplicació tal com era el dia de la primera confirmació: git switch --detach 1a4c8d6, obre index.html al navegador i llestos.
  • Provar si una fallada existia en una versió antiga, situant-se en diferents punts de l'historial.
  • Experimentar sense comprometre's. Pots confirmar en aquest estat, i si el resultat no val, tornes a una branca i els commits queden orfes.

El perill real

El perill no és ser en aquest estat. És confirmar-hi i després marxar sense deixar rastre:

# En detached HEAD
echo "// prova de rendiment" >> app.js
git commit -am "Prova una optimització del pintat"
[detached HEAD 7d2f9a1] Prova una optimització del pintat
 1 file changed, 1 insertion(+)

Aquell commit 7d2f9a1 és real i és a la base de dades d'objectes, però cap branca no l'assoleix. Si l'Ana ara fa git switch main:

Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  7d2f9a1 Prova una optimització del pintat

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 7d2f9a1

Switched to branch 'main'

Git avisa, i fins i tot et dona l'ordre exacta. Però si no llegeixes aquell avís i tanques el terminal, el hash desapareix de la teva vista i el commit queda orfe. Continua sent recuperable durant un temps mitjançant el reflog (mòdul 9), però és una situació que no vols.

Com sortir-ne sense perdre res

Si no has confirmat res (només miraves):

git switch -

O git switch main, o qualsevol branca. No hi ha res a salvar.

Si has confirmat i ho vols conservar, crea una branca abans de marxar:

git switch -c experiment/optimitzacio-pintat
Switched to a new branch 'experiment/optimitzacio-pintat'

Ara HEAD torna a apuntar a una branca, aquella branca apunta a 7d2f9a1, i el commit ja és assolible. Ja no hi ha res orfe.

Si ja has marxat i el commit va quedar enrere, encara pots crear la branca a posteriori, sempre que tinguis el hash (apareix a l'avís, i si el vas perdre, a git reflog):

git branch experiment/optimitzacio-pintat 7d2f9a1
graph TD
    A["En una branca<br/>HEAD → ref: refs/heads/main"] -->|"git switch --detach abc123"| B["HEAD desacoblat<br/>HEAD → abc123"]
    B -->|"git switch -<br/>(sense confirmar res)"| A
    B -->|"confirmar aquí"| C["Commits orfes<br/>cap branca no els assoleix"]
    C -->|"git switch -c la-meva-branca"| D["Feina salvada<br/>en una branca nova"]
    C -->|"marxar sense crear branca"| E["Només recuperable<br/>via reflog (mòdul 9)"]

  1. El repositori de l'equip, ja amb branques

Recapitulem on som. L'Ana té la seva branca amb dos commits. En Bruno ha estat treballant a la seva, amb els tres commits que ja vam veure al final del mòdul 2 —el filtre de pendents, l'estil de les completades i la correcció del focus—, ara a funcionalitat/filtre-pendents en lloc de directament sobre main.

Per a la resta del mòdul raonarem com si les tres branques fossin en un mateix repositori local, el de l'Ana. Com aconsegueix l'equip que la feina viatgi entre el portàtil de l'Ana i el MacBook d'en Bruno és precisament el tema del mòdul 4; aquí ens concentrem en la mecànica de les branques, que és idèntica vingui la feina d'on vingui.

git branch -v
  funcionalitat/comptador-tasques 9d1e4b7 Marca les tasques com a completades en fer clic
  funcionalitat/filtre-pendents   b2e6d3f Corregeix el focus del camp després d'afegir una tasca
* main                            c5d9b1e Documenta la instal·lació al README
git log --oneline --graph --all
* b2e6d3f (funcionalitat/filtre-pendents) Corregeix el focus del camp després d'afegir una tasca
* 7c1f4a9 Aplica estil a les tasques completades
* 3d5b8e1 Afegeix el filtre de tasques pendents
| * 9d1e4b7 (funcionalitat/comptador-tasques) Marca les tasques com a completades en fer clic
| * 6f2b9d4 Afegeix el comptador de tasques pendents
|/
* c5d9b1e (HEAD -> main) Documenta la instal·lació al README
* 4e7f2a9 Afegeix l'esborrat de tasques al llistat
* 8b6d3c2 Afegeix els estils base del llistat
* 1a4c8d6 Estructura inicial del gestor de tasques
gitGraph
   commit id: "1a4c8d6"
   commit id: "8b6d3c2"
   commit id: "4e7f2a9"
   commit id: "c5d9b1e"
   branch comptador-tasques
   checkout comptador-tasques
   commit id: "6f2b9d4"
   commit id: "9d1e4b7"
   checkout main
   branch filtre-pendents
   checkout filtre-pendents
   commit id: "3d5b8e1"
   commit id: "7c1f4a9"
   commit id: "b2e6d3f"

Tres línies de treball, tres punters, 123 bytes de cost total. Els quatre commits de base són una sola vegada a la base de dades d'objectes i els comparteixen les tres branques.

I aquí hi ha el problema que resoldrem a la lliçó següent: les dues funcionalitats estan acabades i provades, però el projecte realmain— continua exactament on era fa una setmana. Res del que han fet l'Ana i en Bruno no és a la línia principal.

Errors Habituals i Consells

Error 1: git branch <nom> i posar-se a treballar. Crees la branca, se t'oblida el git switch, fas cinc commits i tots cauen a main. Prevenció doble: fes servir git switch -c en lloc de git branch, i llegeix la línia entre claudàtors que imprimeix git commit, que et diu la branca de destinació.

Error 2: crear la branca des del lloc equivocat. git switch -c correccio/urgent estant en una branca de funcionalitat a mitges arrossega tota aquella feina sense acabar dins de la correcció urgent. Abans de crear una branca, comprova on ets amb git branch --show-current, o indica el punt de partida explícitament: git switch -c correccio/urgent main.

Error 3: entrar en pànic amb detached HEAD. No és un error ni una corrupció: és un estat normal. El missatge és llarg perquè explica, no perquè avisi d'un desastre. Si només miraves, git switch - i llestos. Si vas confirmar, git switch -c <nom> abans de marxar.

Error 4: fer servir git checkout -f o --discard-changes per «desencallar». Aquella ordre destrueix els canvis no confirmats de manera irreversible: no són a cap objecte de Git i no hi ha reflog que valgui. Quan Git es negui a canviar de branca, la resposta correcta és confirmar, descartar conscientment amb git restore o desar amb git stash.

Error 5: git switch -C en lloc de -c. La majúscula reinicia una branca existent sense preguntar. Si la branca ja tenia feina, mou el punter i aquella feina queda òrfena. -c falla amb un error clar, que en el 99 % dels casos és el que vols que passi.

Consell 1: una branca per tasca, i de vida curta. Les branques són gratis, així que no hi acumulis feina. Una branca que viu tres setmanes acumula divergència i garanteix conflictes; una que viu dos dies gairebé mai no en té.

Consell 2: activa l'autocompletat de Git. Amb noms com funcionalitat/filtre-pendents, escriure git switch fun<TAB> és la diferència entre treballar còmode i equivocar-se de branca. L'script git-completion.bash ve amb la instal·lació de Git i moltes distribucions l'activen per defecte.

Consell 3: comprova on ets abans de confirmar. El cost és un segon:

git branch --show-current

Consell 4: no reutilitzis branques velles per a tasques noves. És temptador (ja tinc la branca proves, la reaprofito), però acaba amb historials que no s'entenen i amb fusions que arrosseguen canvis que ningú no ha demanat. Crea una branca nova i esborra la vella quan ja no serveixi; la neteja és el tema de la lliçó 03-06.

Exercicis

Exercici 1: crear branques sense moure's

En un repositori de proves amb almenys tres commits, crea dues branques —experiment/un i experiment/dos— sense canviar-te a cap d'elles, de manera que:

  • experiment/un parteixi del commit actual.
  • experiment/dos parteixi de dos commits enrere.

Després, demostra amb ordres que HEAD no s'ha mogut i que les dues branques apunten on correspon.

Exercici 2: provocar i resoldre un rebuig de canvi de branca

Dissenya la seqüència mínima d'ordres que provoqui l'error Your local changes to the following files would be overwritten by checkout, i després resol-lo de tres maneres diferents, explicant quan faries servir cadascuna.

Exercici 3: sortir d'un HEAD desacoblat sense perdre feina

Situa't deliberadament en un HEAD desacoblat, fes-hi un commit i conserva'l en una branca nova. Després repeteix el procés però abandonant l'estat sense crear la branca, i observa què et diu Git. Quina dada del missatge és imprescindible anotar?

Solucions

Solució 1:

# Punt de partida: comprovem on som
git branch --show-current
main
git rev-parse HEAD
c5d9b1e7a3f2d8b4e6c1a9f5d3b7e2c8a4f6d1b9
# Les dues branques, amb git branch (que NO mou HEAD)
git branch experiment/un
git branch experiment/dos HEAD~2

Comprovació:

git branch -v
  experiment/dos  8b6d3c2 Afegeix els estils base del llistat
  experiment/un   c5d9b1e Documenta la instal·lació al README
* main            c5d9b1e Documenta la instal·lació al README

L'asterisc continua a main: HEAD no s'ha mogut. experiment/un coincideix amb main i experiment/dos és dos commits enrere, com demanava l'enunciat.

Verificació byte a byte:

cat .git/HEAD
ref: refs/heads/main
git rev-parse experiment/un experiment/dos
c5d9b1e7a3f2d8b4e6c1a9f5d3b7e2c8a4f6d1b9
8b6d3c2e1f5a9c3d7b2e6f8a4c1d9b3e5f7a2c6e

Solució 2:

Per provocar l'error calen dues condicions: un fitxer que difereixi entre les dues branques i una modificació sense confirmar en aquell mateix fitxer.

# 1. Branca amb un canvi confirmat a app.js
git switch -c branca-x
echo "// canvi de la branca X" >> app.js
git commit -am "Canvia app.js a la branca X"

# 2. Tornem a main i toquem el MATEIX fitxer, sense confirmar
git switch main
echo "// canvi sense confirmar a main" >> app.js

# 3. Intentem tornar
git switch branca-x
error: Your local changes to the following files would be overwritten by checkout:
	app.js
Please commit your changes or stash them before you switch branches.
Aborting

Les tres resolucions:

# A) Confirmar: la feina pertany a main i està llesta
git commit -am "Afegeix una nota a app.js"
git switch branca-x

Quan: quan el canvi és vàlid i té sentit a la branca actual.

# B) Descartar: el canvi no serveix
git restore app.js
git switch branca-x

Quan: proves, traces de depuració o qualsevol cosa que no vulguis conservar. És irreversible.

# C) Desar temporalment: feina a mitges que vull conservar
git stash
git switch branca-x
# … feina a branca-x …
git switch main
git stash pop

Quan: el cas més habitual del dia a dia, i el motiu que git stash existeixi (lliçó 05-04).

Solució 3:

# Ens desacoblem deliberadament
git switch --detach HEAD~2
HEAD is now at 8b6d3c2 Afegeix els estils base del llistat
# Confirmem alguna cosa aquí
echo "/* prova des de HEAD desacoblat */" >> estils.css
git commit -am "Prova un ajust d'estils"
[detached HEAD 5f7a9c1] Prova un ajust d'estils
 1 file changed, 1 insertion(+)
# El conservem ABANS de marxar
git switch -c experiment/ajust-estils
Switched to a new branch 'experiment/ajust-estils'
git log --oneline -1
5f7a9c1 (HEAD -> experiment/ajust-estils) Prova un ajust d'estils

El commit ja és assolible des d'una branca: no hi ha res orfe.

Segona part, abandonant sense crear branca:

git switch --detach HEAD~2
echo "/* una altra prova */" >> estils.css
git commit -am "Una altra prova que abandonaré"
git switch main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  3c9d4a2 Una altra prova que abandonaré

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 3c9d4a2

Switched to branch 'main'

La dada imprescindible és el hash: 3c9d4a2. Mentre el tinguis, recuperar la feina és una sola ordre:

git branch rescat 3c9d4a2

Si a més perds el hash, la situació no és desesperada: git reflog guarda tots els moviments de HEAD durant 90 dies per defecte i permet trobar-lo. És el tema de la lliçó 09-04.

Conclusió

Ja saps crear branques i moure't entre elles amb criteri:

  • git branch <nom> crea el punter i no toca res més: ni HEAD, ni el directori de treball, ni l'índex. Útil per marcar un punt sense abandonar el que estàs fent.
  • git switch <branca> et situa en una branca: reescriu .git/HEAD i actualitza el directori de treball a l'arbre de destinació.
  • git switch -c <nom> [punt-de-partida] és la manera habitual de començar una tasca: crea i es canvia en un pas, i admet qualsevol referència com a origen (una altra branca, un hash, HEAD~2…).
  • git switch i git restore substitueixen git checkout des de Git 2.23, separant el que abans era una única ordre ambigua: navegar entre branques i destruir canvis ja no comparteixen verb. checkout continua funcionant i el continuaràs veient en documentació i scripts.
  • git switch - alterna amb la branca anterior, igual que cd -.
  • En canviar de branca, Git s'emporta els canvis sense confirmar si pot fer-ho sense perdre res, i avorta netament si el fitxer difereix entre les dues branques. Les sortides són confirmar, descartar amb git restore o apartar amb git stash (lliçó 05-04).
  • El HEAD desacoblat és HEAD contenint un hash en lloc de ref: refs/heads/…. No és un error: serveix per inspeccionar i experimentar. L'única precaució és crear una branca amb git switch -c abans d'abandonar-lo si hi has confirmat alguna cosa.

El que ve

L'equip té ara tres branques: main aturada on era, funcionalitat/comptador-tasques amb dos commits de l'Ana i funcionalitat/filtre-pendents amb tres d'en Bruno. Dues funcionalitats acabades que no són al projecte.

Aïllar la feina era la meitat del problema; l'altra meitat és tornar-la a ajuntar. A la lliçó següent, Fusionant Branques, l'Ana integrarà per fi les dues funcionalitats a main. Veurem els dos escenaris que Git distingeix —el fast-forward, en què el punter simplement avança, i la fusió a tres bandes, que crea un commit especial amb dos pares—, com troba Git l'ancestre comú que vam estudiar a la lliçó anterior, i per què de vegades convé forçar un commit de fusió encara que no calgui.

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