Vam tancar el mòdul 1 amb el portàtil de l'Ana a punt: Git instal·lat, la identitat configurada, init.defaultBranch valent main i l'editor llest. Tota la bastida estava muntada, però gestor-tasques continuava sent el que era el primer dia: una carpeta normal i corrent amb quatre fitxers a dins. Ni historial, ni versions, ni cap manera de tornar enrere.

En aquesta lliçó fem el pas que ho canvia tot. Amb una sola ordre, git init, aquella carpeta passa a ser un repositori: Git comença a observar-la, apareix el directori .git/ amb la base de dades d'objectes que vam estudiar a El Model de Dades de Git, i a partir d'aquí cada canvi pot quedar registrat per sempre.

Veurem què crea exactament git init, què diu git status en un repositori acabat de néixer (i per què parla de "no commits yet"), com es crea la primera confirmació del projecte, en què es diferencia arrencar de zero de convertir un projecte que ja existeix, i com desfer un git init llançat per error al lloc equivocat —una cosa que li passa a gairebé tothom alguna vegada.

Contingut

  1. El punt de partida: la carpeta de l'Ana
  2. git init: l'ordre que crea el repositori
  3. Què crea exactament dins de .git/
  4. git status en un repositori acabat de crear
  5. Què significa "No commits yet"
  6. La primera confirmació del projecte
  7. Convertir un projecte existent enfront de començar de zero
  8. Repositoris bare: què són i per a què serveixen
  9. Com desfer un git init accidental
  10. Comprovacions útils abans de continuar

  1. El punt de partida: la carpeta de l'Ana

L'Ana treballa en Ubuntu i té el seu projecte a ~/projectes/gestor-tasques. L'ha escrit durant un parell de tardes i conté quatre fitxers:

cd ~/projectes/gestor-tasques
ls -l
total 16
-rw-rw-r-- 1 ana ana  486 jul 20 18:12 app.js
-rw-rw-r-- 1 ana ana  312 jul 20 17:55 estils.css
-rw-rw-r-- 1 ana ana  602 jul 20 18:04 index.html
-rw-rw-r-- 1 ana ana  198 jul 20 18:20 README.md

El contingut és senzill. index.html munta la pàgina:

<!DOCTYPE html>
<html lang="ca">
<head>
  <meta charset="utf-8">
  <title>Gestor de Tasques</title>
  <link rel="stylesheet" href="estils.css">
</head>
<body>
  <h1>Gestor de Tasques</h1>
  <form id="nova-tasca">
    <input type="text" id="text" placeholder="Què cal fer?">
    <button type="submit">Afegeix</button>
  </form>
  <ul id="llista"></ul>
  <script src="app.js"></script>
</body>
</html>

I app.js conté la lògica mínima per afegir tasques:

// gestor-tasques — lògica principal
const tasques = [];

function afegeixTasca(text) {
  tasques.push({ id: Date.now(), text: text, feta: false });
  pintaLlista();
}

function pintaLlista() {
  const llista = document.querySelector('#llista');
  llista.innerHTML = '';
  for (const tasca of tasques) {
    const li = document.createElement('li');
    li.textContent = tasca.text;
    llista.appendChild(li);
  }
}

document.querySelector('#nova-tasca').addEventListener('submit', function (esdeveniment) {
  esdeveniment.preventDefault();
  const camp = document.querySelector('#text');
  if (camp.value.trim() !== '') {
    afegeixTasca(camp.value.trim());
    camp.value = '';
  }
});

Aquests fitxers ens acompanyaran durant tot el curs. Fixa't en un detall que importarà més endavant: no hi ha cap carpeta oculta. Comprovem-ho:

ls -a
.  ..  app.js  estils.css  index.html  README.md

Només hi ha . (el directori actual) i .. (el pare). Ni rastre de .git. Això és el que Git anomena, amb precisió, un directori que no està sota control de versions. Si l'Ana esborrés app.js ara mateix, no hi hauria res a fer.

  1. git init: l'ordre que crea el repositori

L'Ana se situa dins de la carpeta del projecte i executa:

cd ~/projectes/gestor-tasques
git init
Initialized empty Git repository in /home/ana/projectes/gestor-tasques/.git/

Ja està. Això és tot. Analitzem el missatge amb calma, perquè cada paraula diu alguna cosa:

  • Initialized: s'ha creat l'estructura des de zero.
  • empty: el repositori està buit en el sentit que no conté cap confirmació. Compte: els quatre fitxers de l'Ana continuen allà intactes. "Buit" es refereix a l'historial, no a la carpeta.
  • La ruta /home/ana/projectes/gestor-tasques/.git/: t'indica exactament on ha quedat el repositori. Val la pena llegir-la sempre, perquè és la manera més ràpida de detectar que l'has executat al lloc equivocat.

Les dues maneres d'invocar-lo

Forma Què fa Quan fer-la servir
git init Converteix el directori actual en repositori Ja tens una carpeta amb fitxers (el cas de l'Ana)
git init <nom> Crea el directori <nom> si no existeix i l'inicialitza Comences un projecte de zero

La segona forma estalvia un pas. Si l'Ana comencés un projecte nou anomenat notes-equip:

cd ~/projectes
git init notes-equip
Initialized empty Git repository in /home/ana/projectes/notes-equip/.git/
ls -a notes-equip
.  ..  .git

Git ha creat la carpeta i l'ha inicialitzada, però no hi ha posat res a dins: el projecte està per escriure.

Opcions que convé conèixer

# Forçar el nom de la branca inicial en aquest repositori concret
git init --initial-branch=main
git init -b main          # forma abreujada

# Inicialitzar amb sortida mínima
git init --quiet

L'Ana no necessita -b main perquè ja va fixar init.defaultBranch=main a la seva configuració global a Configuració Inicial. Però si treballes en un equip on no tothom ho té configurat, git init -b main garanteix el mateix punt de partida per a tothom.

Nota sobre versions antigues. L'opció -b / --initial-branch existeix des de Git 2.28. En versions anteriors la branca inicial sempre s'anomenava master i no hi havia manera de canviar-la en el moment de crear el repositori. Si el teu git --version és inferior a 2.28, aquest és un bon motiu per actualitzar.

  1. Què crea exactament dins de .git/

Ara sí, vegem què ha aparegut:

ls -a
.  ..  .git  app.js  estils.css  index.html  README.md

L'únic canvi visible és la carpeta .git. Mirem-hi dins:

ls -F .git
branches/  config  description  HEAD  hooks/  info/  objects/  refs/

Això connecta directament amb el que vam veure a El Model de Dades de Git. Repassem què és cada peça en un repositori acabat d'inicialitzar:

Element Què és Estat acabat de crear
HEAD Referència a la branca actual Apunta a refs/heads/main, que encara no existeix
config Configuració de nivell --local Només uns quants valors per defecte
description Nom del repositori per a GitWeb Text de farciment; irrellevant avui
objects/ La base de dades d'objectes Buida: sense blobs, sense trees, sense commits
refs/ Branques (heads/) i etiquetes (tags/) Tots dos subdirectoris buits
hooks/ Scripts que es disparen en certs esdeveniments Només exemples desactivats (.sample)
info/ Informació auxiliar, com ara exclude Pràcticament buit
branches/ Directori heretat, en desús Buit; el pots ignorar

Fixa't en el que no hi ha: no hi ha fitxer index. L'àrea de preparació és un fitxer binari (.git/index) que Git crea la primera vegada que prepares alguna cosa. Abans d'això, senzillament no existeix.

Mirant els fitxers clau

HEAD és un fitxer de text d'una sola línia:

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

Diu: "la branca actual és main". Però ara mateix aquesta branca és una promesa, no un fet:

ls .git/refs/heads
(no mostra res)

El directori és buit. main no existeix com a fitxer de referència perquè una branca és, literalment, un fitxer que conté el hash d'una confirmació, i encara no hi ha cap confirmació a la qual apuntar. Aquesta situació —HEAD apuntant a una branca inexistent— s'anomena branca òrfena o unborn branch, i es resol tota sola tan bon punt es crea el primer commit.

El config local també és curt:

cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true

Quatre valors tècnics i res més. Recorda de Configurant Git que aquest fitxer és el nivell --local, el de més precedència: la identitat de l'Ana no és aquí perquè la va posar a --global, i des d'allà s'aplica igualment.

I la base de dades d'objectes està estrictament buida:

find .git/objects -type f
(no mostra res)
ls .git/objects
info  pack

Dos subdirectoris buits esperant el primer blob. Això il·lustra bé la idea de fons: git init no desa cap dels teus fitxers. Només prepara el magatzem. Desar és cosa de git add i git commit.

  1. git status en un repositori acabat de crear

git status és l'ordre que més vegades escriuràs a la teva vida. Vegem què diu ara:

git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	README.md
	app.js
	estils.css
	index.html

nothing added to commit but untracked files present (use "git add" to track)

Quatre blocs d'informació, i tots importen:

  1. On branch main — en quina branca ets. Coincideix amb el que vam llegir a .git/HEAD.
  2. No commits yet — l'historial és buit. Ho desenvolupem a l'apartat següent.
  3. Untracked files — els fitxers sense seguiment. Git els veu al directori de treball, però no els ha registrat mai, així que encara no formen part del projecte. És l'estat que vam presentar a Terminologia Bàsica de Git.
  4. L'última línia — un resum: no hi ha res preparat, però sí fitxers sense seguiment.

Observa el detall que Git suggereix l'ordre següent entre parèntesis: use "git add <file>...". Git és insistentment pedagògic a la seva sortida. Llegir aquests suggeriments en lloc de saltar-se'ls escurça moltíssim la corba d'aprenentatge.

Consell. Si aquests suggeriments et resulten sorollosos quan ja dominis el flux, els pots reduir amb git config --global advice.statusHints false. Al principi, deixa'ls.

  1. Què significa "No commits yet"

És una frase que confon el principiant perquè sembla dir "no has fet res", quan en realitat té un significat tècnic molt concret:

HEAD apunta a la branca main, però main no apunta a cap confirmació.

És un estat transitori i perfectament vàlid, però té conseqüències pràctiques. Moltes ordres necessiten una confirmació de referència i fallen fins que n'existeixi la primera:

git log
fatal: your current branch 'main' does not have any commits yet
git diff HEAD
fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.

No és un error teu: és que HEAD no resol a res. Tan bon punt hi hagi un commit, totes aquestes ordres funcionaran amb normalitat.

Ho podem veure amb la lampisteria que vam aprendre al mòdul 1:

git rev-parse HEAD
HEAD
fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.

Aquest diagrama resumeix l'estat del repositori de l'Ana en aquest moment:

graph LR
    HEAD["HEAD"] -->|ref: refs/heads/main| MAIN["main<br/>(encara no existeix)"]
    MAIN -.->|apuntarà a| C["primer commit<br/>(encara sense crear)"]
    OBJ["objects/<br/>buit"]
    WT["Directori de treball<br/>4 fitxers sense seguiment"]

    style MAIN stroke-dasharray: 5 5
    style C stroke-dasharray: 5 5

  1. La primera confirmació del projecte

Tanquem el cercle. A Flux de Treball Bàsic de Git i sobretot a Preparant i Confirmant Canvis veurem aquestes ordres amb tot detall; aquí les fem servir en la seva forma més simple perquè el repositori deixi d'estar buit.

Pas 1: preparar els quatre fitxers.

git add README.md app.js estils.css index.html

L'ordre no imprimeix res. En Git, el silenci significa èxit. Comprovem-ne l'efecte:

git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md
	new file:   app.js
	new file:   estils.css
	new file:   index.html

Els quatre fitxers han passat d'Untracked files a Changes to be committed: són a l'àrea de preparació. Cadascun apareix marcat com a new file perquè no existien en cap confirmació anterior (no n'hi ha cap).

I ara sí que existeix l'índex:

ls .git/index
.git/index

I la base de dades ja té contingut:

find .git/objects -type f | wc -l
4

Quatre objectes: un blob per cada fitxer. Encara no hi ha ni arbre ni commit; això ho crea git commit.

Pas 2: confirmar.

git commit -m "Estructura inicial del gestor de tasques"
[main (root-commit) 1a4c8d6] Estructura inicial del gestor de tasques
 4 files changed, 68 insertions(+)
 create mode 100644 README.md
 create mode 100644 app.js
 create mode 100644 estils.css
 create mode 100644 index.html

Llegim la primera línia, que és la més informativa:

  • [main — la branca sobre la qual s'ha confirmat.
  • (root-commit) — aquesta marca només apareix a la primera confirmació d'un historial: és un commit sense pare. Recorda del model de dades que un commit normal desa el hash del seu pare; aquest no en té cap.
  • 1a4c8d6 — el hash abreujat del nou commit.
  • El missatge que hem escrit.

Les línies següents resumeixen què hi ha entrat: 4 fitxers, 68 línies afegides, i el mode 100644 (fitxer normal) de cadascun, exactament la notació que vam veure en estudiar els trees.

Pas 3: comprovar el resultat.

git status
On branch main
nothing to commit, working tree clean

Han desaparegut tant No commits yet com la llista de fitxers. working tree clean significa que el directori de treball coincideix exactament amb l'última confirmació: no hi ha res pendent. És el missatge més tranquil·litzador de Git.

I la branca ja existeix de debò:

cat .git/refs/heads/main
1a4c8d6f2b9e5a3c7d1f4b8e6a2c9d5f3b7e1a4c

Un fitxer amb un hash a dins. Això és una branca en Git: ni més ni menys.

git log --oneline
1a4c8d6 (HEAD -> main) Estructura inicial del gestor de tasques

HEAD -> main indica que estem situats a la branca main i que aquesta branca apunta a aquest commit. El projecte de l'Ana ja té història.

  1. Convertir un projecte existent enfront de començar de zero

Els dos escenaris fan servir la mateixa ordre, però les precaucions són diferents.

Començar de zero Convertir projecte existent
Ordre típica git init <nom> cd projecte && git init
Estat inicial Carpeta buida Fitxers ja presents, sense seguiment
Risc principal Cap Confirmar brossa: dependències, secrets, binaris
Pas previ recomanat Crear un README.md Escriure un .gitignore abans del primer git add
Primer commit Gairebé buit Tot el projecte de cop

El risc del segon cas és real i molt freqüent. Imagina que l'Ana hagués instal·lat dependències abans d'inicialitzar el repositori:

git status --short
?? README.md
?? app.js
?? estils.css
?? index.html
?? node_modules/
?? .env

Si fes git add . sense pensar, ficaria a l'historial milers de fitxers de node_modules/ (que es reinstal·len amb una ordre i no aporten res) i, molt pitjor, .env amb les seves claus. I com vam aprendre a El Model de Dades de Git, l'historial és immutable: treure'n un fitxer amb secrets no és "esborrar-lo", és reescriure l'historial i rotar les claus.

La regla és senzilla: en un projecte existent, escriu el .gitignore abans del primer git add. Un .gitignore mínim per al cas de l'Ana:

node_modules/
.env
*.log
.DS_Store

Amb això, git status torna a mostrar només el que interessa. Veurem els patrons, les excepcions i els casos difícils a Ignorant Fitxers amb .gitignore; de moment queda't amb la idea que aquest fitxer existeix i que el seu lloc és abans del primer commit.

Un detall important: els fitxers existents no es perden

Convé dir-ho explícitament perquè genera ansietat: git init no toca els teus fitxers. No els mou, no els modifica, no els esborra. Només crea .git/. Si executes git init en una carpeta amb feina de mesos, aquesta feina continua exactament igual un segon després. L'única cosa que canvia és que ara pots començar a versionar-la.

  1. Repositoris bare: què són i per a què serveixen

Existeix una variant que veuràs esmentada constantment:

git init --bare gestor-tasques.git

Un repositori bare (nu) és un repositori sense directori de treball. No conté index.html ni app.js com a fitxers amb els quals puguis treballar: conté únicament la base de dades d'objectes i les referències, és a dir, el contingut del que en un repositori normal seria .git/, però directament a l'arrel.

ls -F gestor-tasques.git
config  description  HEAD  hooks/  info/  objects/  refs/

Et sona? És exactament el mateix contingut que vam veure dins de .git/, però sense carpeta contenidora i sense fitxers del projecte al costat.

Repositori normal Repositori bare
Directori de treball No
Pots editar fitxers No
Hi pots confirmar No directament
Convenció de nom gestor-tasques gestor-tasques.git
Ús típic La teva còpia de treball Servidor central compartit

Per a què serveix: és la manera correcta de muntar el repositori "central" al qual tot l'equip envia i del qual tot l'equip descarrega. Quan clones de GitHub o GitLab, el que hi ha a l'altra banda és un repositori bare. Es fa així perquè, si el repositori central tingués directori de treball, rebre canvis el podria deixar en un estat incoherent respecte del que hi hagués als seus fitxers.

No ho desenvolupem més aquí: els repositoris bare cobren sentit quan parlem de remots al mòdul 4. Queda't amb la definició —repositori sense còpia de treball, pensat per compartir— i amb el fet que a la lliçó següent en Bruno clonarà precisament d'un.

  1. Com desfer un git init accidental

Li passa a tothom: executes git init, mires el missatge i descobreixes una ruta que no esperaves. El cas clàssic:

cd ~
git init
Initialized empty Git repository in /home/ana/.git/

Acabes de convertir tota la teva carpeta personal en un repositori. git status intentarà llistar desenes de milers de fitxers sense seguiment i, encara pitjor, qualsevol projecte que tinguis a dins començarà a comportar-se de manera estranya, perquè Git busca el .git més proper cap amunt i ara troba aquest.

La solució és tranquil·litzadora per la seva simplicitat: esborrar la carpeta .git.

cd ~
rm -rf .git

En Windows, des de PowerShell:

Remove-Item -Recurse -Force .git

Això és tot. Com que git init no havia fet res més que crear aquesta carpeta, esborrar-la retorna el sistema exactament a com estava. Els teus fitxers no en resulten afectats en absolut.

Precaucions abans d'esborrar

Aquí convé anar amb compte, perquè rm -rf .git és inofensiu en un repositori acabat d'inicialitzar i catastròfic en un amb historial: esborraries tots els commits, branques i etiquetes, i no hi hauria manera de recuperar-los (llevat que existeixi una còpia en un altre lloc). Abans d'executar-lo, fes-te tres preguntes:

1. Sóc on em penso que sóc?

pwd

2. Quin és el repositori que vaig a esborrar?

git rev-parse --show-toplevel
/home/ana

Aquesta ordre retorna l'arrel del repositori actual, que és justament el que eliminaràs. Si la ruta no és la que esperaves, no esborris res encara.

3. Té historial?

git log --oneline

Si respon does not have any commits yet, esborrar és segur. Si llista confirmacions, atura't i esbrina quin repositori és abans de tocar res.

Com evitar-ho la propera vegada

  • Llegeix sempre la ruta del missatge d'Initialized.... Un segon d'atenció evita el problema sencer.
  • Prefereix git init <nom> quan comencis de zero: crea la carpeta ell mateix, així que no et pots equivocar de lloc.
  • Comprova abans d'inicialitzar si ja ets dins d'un repositori:
git rev-parse --is-inside-work-tree
fatal: not a git repository (or any of the parent directories): .git

Aquest fatal és, en aquest cas, la resposta que vols: significa que no ets dins de cap repositori i que git init en crearà un de nou de debò.

Un avís sobre repositoris imbricats. Si executes git init dins d'una carpeta que ja està sota control de versions, Git no protesta: crees un repositori dins d'un altre. El repositori interior queda invisible per a l'exterior i sol acabar en confusió i feina perduda. Si de debò necessites imbricar projectes, l'eina correcta són els submòduls, no un git init a mà.

  1. Comprovacions útils abans de continuar

Un grapat d'ordres de diagnòstic que convé tenir a mà:

# Sóc dins d'un repositori?
git rev-parse --is-inside-work-tree     # → true

# Quina és l'arrel del repositori?
git rev-parse --show-toplevel           # → /home/ana/projectes/gestor-tasques

# On és el directori .git?
git rev-parse --git-dir                 # → .git

# És un repositori bare?
git rev-parse --is-bare-repository      # → false

# En quina branca sóc?
git branch --show-current               # → main

# Amb quina identitat confirmaré aquí?
git config user.name && git config user.email

Aquesta última és especialment valuosa quan fas servir perfils condicionals amb includeIf, com vam veure al final de Configurant Git: et confirma quina identitat s'aplicarà en aquest repositori concret abans de crear una confirmació amb el correu equivocat.

Errors Habituals i Consells

  • Executar git init sense mirar on ets. És l'error número u. Llegeix la ruta del missatge de confirmació; si no és l'esperada, esborra .git immediatament abans d'afegir-hi res.
  • Creure que git init ja desa els fitxers. No desa res. Un repositori acabat d'inicialitzar té la base de dades buida i tots els teus fitxers en estat untracked. Fins al primer git commit no hi ha cap còpia de seguretat de res.
  • Fer git add . com a primera ordre en un projecte existent. Sense .gitignore, arrossegaràs dependències, fitxers temporals, binaris de compilació i, en el pitjor dels casos, secrets. Escriu primer el .gitignore i revisa git status abans de preparar.
  • Confondre "repositori buit" amb "carpeta buida". El missatge Initialized empty Git repository alarma molta gent que tem haver perdut la seva feina. "Buit" es refereix a l'historial, no als fitxers.
  • Inicialitzar un repositori dins d'un altre. Git ho permet en silenci i el resultat és desconcertant. Comprova-ho abans amb git rev-parse --show-toplevel.
  • No confirmar res durant dies. Un repositori sense commits no et protegeix de res. La primera confirmació, encara que sigui imperfecta, ja és una xarxa de seguretat.
  • Consell: acostuma't que el primer commit d'un projecte s'anomeni alguna cosa com ara "Estructura inicial del projecte". És la convenció més estesa i ajuda a localitzar l'origen de l'historial d'un cop d'ull.
  • Consell: si tens dubtes sobre si una carpeta és un repositori, ls -a en Linux/macOS o dir /a en Windows t'ho diu en un segon: si hi apareix .git, ho és.

Exercicis

Exercici 1: Crear un repositori de zero i observar-lo

Crea un repositori nou anomenat notes-equip sense fer servir mkdir, i respon amb ordres —no de memòria— a aquestes quatre preguntes:

  1. A quina branca apunta HEAD?
  2. Existeix ja aquesta branca com a fitxer a refs/heads?
  3. Quants objectes hi ha a la base de dades?
  4. Existeix el fitxer .git/index?

Després crea un README.md amb una línia de text, fes la primera confirmació i torna a respondre les quatre preguntes. Explica què ha canviat i per què.

Exercici 2: Convertir un projecte existent sense ficar-hi brossa

Prepara aquesta situació de partida:

mkdir -p ~/practica/botiga-online/node_modules/llibreria
cd ~/practica/botiga-online
echo "<h1>Botiga</h1>" > index.html
echo "body { margin: 0; }" > estils.css
echo "API_KEY=abc123secret" > .env
echo "soroll" > node_modules/llibreria/index.js
echo "error de dijous" > depuracio.log

Converteix la carpeta en repositori i fes un primer commit que contingui exclusivament index.html, estils.css i el .gitignore. Demostra amb la sortida de git status que .env, node_modules/ i depuracio.log no apareixen ni tan sols com a fitxers sense seguiment.

Exercici 3: Diagnosticar i reparar un git init accidental

Un company t'escriu: "he executat git init no sé on i ara git status triga moltíssim i em llista milers de fitxers que no són del meu projecte. A més, quan entro a la meva carpeta ~/projectes/api-clients i faig git log, em diu que no hi ha confirmacions, quan jo sé que en porto vint."

  1. Què ha passat, exactament?
  2. Quines ordres ha d'executar per confirmar el diagnòstic abans de tocar res?
  3. Com ho arregla sense perdre l'historial d'api-clients?
  4. Per què git log a api-clients deia que no hi havia confirmacions si el .git d'aquest projecte continuava intacte?

Solucions

Solució a l'Exercici 1

cd ~/projectes
git init notes-equip
cd notes-equip

Estat inicial:

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

ls .git/refs/heads
# → (buit)

find .git/objects -type f | wc -l
# → 0

ls .git/index
# → ls: cannot access '.git/index': No such file or directory

Respostes: (1) HEAD apunta a refs/heads/main; (2) no, la branca encara no existeix; (3) zero objectes; (4) no existeix l'índex.

Després de la primera confirmació:

echo "# Notes de l'equip" > README.md
git add README.md
git commit -m "Estructura inicial del projecte"
[main (root-commit) 3f7b2e9] Estructura inicial del projecte
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
cat .git/HEAD
# → ref: refs/heads/main            (sense canvis)

cat .git/refs/heads/main
# → 3f7b2e9c1a5d8b4f2e6a9c3d7b1f5e8a4c2d9b6f    (ara sí que existeix)

find .git/objects -type f | wc -l
# → 3

ls .git/index
# → .git/index                      (ara sí que existeix)

Què ha canviat i per què:

  • HEAD continua igual. Sempre apuntava a main; el que faltava era la branca, no la referència.
  • main ja existeix com a fitxer amb un hash a dins: el commit ha donat a la branca alguna cosa a la qual apuntar. Aquí es veu literalment que una branca és un fitxer de text amb un hash.
  • Hi ha 3 objectes, no 1. Són els tres objectes que exigeix el model de dades de 01-04: un blob amb el contingut de README.md, un tree amb el directori arrel (una entrada: el nom README.md i el hash del blob) i un commit que apunta a aquest tree i no té pare.
  • .git/index existeix perquè git add el va crear en preparar el fitxer.

Solució a l'Exercici 2

L'ordre dels passos és el que resol l'exercici: primer el .gitignore, després git add.

cd ~/practica/botiga-online
git init
Initialized empty Git repository in /home/ana/practica/botiga-online/.git/

Abans de preparar res, escrivim les exclusions:

cat > .gitignore <<'FI'
node_modules/
.env
*.log
FI

Comprovació:

git status --short
?? .gitignore
?? estils.css
?? index.html

.env, node_modules/ i depuracio.log han desaparegut de la llista: Git els veu al disc però els ignora, així que ni tan sols els compta com a untracked. Aquesta és la demostració que demanava l'enunciat.

Ara ja és segur preparar-ho tot:

git add .
git commit -m "Estructura inicial de la botiga"
[main (root-commit) 8c2f5a1] Estructura inicial de la botiga
 3 files changed, 5 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 estils.css
 create mode 100644 index.html

Tres fitxers, els tres correctes.

Si algú hagués fet git add . abans de crear el .gitignore, el fitxer .env ja seria a l'àrea de preparació i afegir el .gitignore després no l'en trauria: .gitignore només afecta els fitxers sense seguiment. Caldria treure'l explícitament de l'índex, una cosa que veurem a Preparant i Confirmant Canvis. I si ja s'hagués confirmat, el secret quedaria a l'historial de manera permanent i caldria rotar la clau.

Solució a l'Exercici 3

1. Què ha passat. Ha executat git init al seu directori personal (~) o a ~/projectes, és a dir, en una carpeta per sobre dels seus projectes. Ara existeix un .git en aquest nivell superior.

Els dos símptomes s'expliquen sols:

  • git status llista milers de fitxers perquè el repositori abasta tota la carpeta personal i tot està sense seguiment.
  • Dins d'api-clients veu un historial buit perquè... en realitat no el veu. Vegeu el punt 4.

2. Confirmar el diagnòstic sense modificar res:

cd ~/projectes/api-clients
git rev-parse --show-toplevel
# → /home/company          ← l'arrel NO és api-clients: aquí hi ha el problema

git rev-parse --git-dir
# → /home/company/.git

ls -d ~/.git
# → /home/company/.git     ← existeix, no hauria de ser-hi

I comprovar que el repositori accidental està realment buit abans d'esborrar-lo:

git -C ~ log --oneline
# → fatal: your current branch 'main' does not have any commits yet

Aquest fatal és el llum verd: no hi ha historial a perdre.

3. La reparació:

rm -rf ~/.git

I verificar que tot ha tornat al seu lloc:

cd ~/projectes/api-clients
git rev-parse --show-toplevel
# → /home/company/projectes/api-clients

git log --oneline | head -3
# → les seves vint confirmacions, intactes

4. Per què git log fallava. Perquè Git busca el directori .git pujant per l'arbre de directoris des d'on ets, i fa servir el primer que troba. L'esperable és que el primer sigui el d'api-clients... i així era. Aquí hi ha la clau de l'enunciat: el company no era dins d'api-clients quan va llançar git log, o bé el .git del seu projecte no existia perquè no el va crear mai a dins i havia estat treballant, sense saber-ho, contra el repositori de nivell superior.

Aquest matís és el que fa perillós el git init accidental: el .git de dalt no oculta el de baix, però sí que captura qualsevol ordre que executis en carpetes que no tinguin el seu propi repositori. Si el company portava dies fent commits des de ~ creient que anaven a api-clients, tot el seu historial era a ~/.git i esborrar-lo amb rm -rf el destruiria. D'aquí la insistència de l'apartat 9: comprova sempre git log --oneline abans d'esborrar. Si hagués llistat confirmacions, la solució no seria esborrar, sinó moure aquest .git a un lloc segur i recuperar-ne la feina.

Conclusió

El projecte de l'Ana ja no és una carpeta: és un repositori. En aquesta lliçó hem vist que:

  • git init converteix el directori actual en repositori, i git init <nom> crea a més la carpeta. El seu únic efecte és crear .git/; no toca ni desa els teus fitxers.
  • El que crea és la bastida buida que ja coneixíem del model de dades: HEAD apuntant a main, objects/ sense cap objecte, refs/heads/ sense cap branca i ni tan sols un fitxer index.
  • git status és la brúixola des del primer segon: ens diu la branca, que encara no hi ha confirmacions i quins fitxers estan sense seguiment, suggerint sempre l'ordre següent.
  • "No commits yet" té un significat tècnic: HEAD apunta a una branca que encara no existeix. Per això git log i git diff HEAD fallen fins a la primera confirmació.
  • La primera confirmació és un root-commit: l'únic commit de l'historial sense pare. En crear-la apareixen els blobs, el tree i el commit, i refs/heads/main neix com a fitxer amb un hash a dins.
  • Convertir un projecte existent exigeix una precaució extra: escriure el .gitignore abans del primer git add, perquè l'historial és immutable i treure'n un secret és molt més car que no ficar-l'hi.
  • Els repositoris bare són repositoris sense còpia de treball, pensats per servir de punt central compartit.
  • Un git init accidental es desfà esborrant .git, però només després de comprovar amb git rev-parse --show-toplevel i git log --oneline que aquest repositori no conté res valuós.

L'Ana té el seu repositori i el seu primer commit. Però un projecte d'equip no viu en un sol portàtil: en Bruno s'incorpora la setmana que ve i necessita la seva pròpia còpia, amb tot l'historial, al seu MacBook. Per a això no serveix git init —això crearia un repositori nou i buit, sense relació amb el de l'Ana— sinó una ordre diferent.

A la lliçó següent, Clonant un Repositori, veurem què fa realment git clone: com copia tota la base de dades d'objectes, crea el directori de treball, registra el remot origin i deixa en Bruno amb un historial idèntic al de l'Ana. Compararem els protocols disponibles (HTTPS, SSH i ruta local), les opcions més útils com --branch i --depth, i deixarem clara d'una vegada la diferència conceptual entre init i clone.

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