A la lliçó anterior l'Ana va convertir la seva carpeta en un repositori i va crear la primera confirmació del projecte. Des d'aleshores hi ha treballat uns dies més i l'historial de gestor-tasques ja té diverses confirmacions. A més, l'equip ha publicat el repositori en un servidor intern per poder-lo compartir.

Avui s'incorpora en Bruno, que treballa en macOS. En Bruno necessita el projecte al seu portàtil, però no una còpia qualsevol: necessita els fitxers i tot l'historial, per poder consultar per què es va fer cada canvi, comparar versions i, més endavant, aportar-hi les seves. Baixar-se un .zip li donaria els fitxers d'avui i res més: zero historial, zero context, zero capacitat de col·laborar.

L'eina correcta és git clone. En aquesta lliçó veurem què fa realment —que és bastant més que copiar fitxers—, quins protocols existeixen per accedir a un repositori remot i en què es diferencien, les opcions que més es fan servir en el dia a dia (--branch, --depth, --single-branch) i, sobretot, quan es fa servir clone i quan init, que és un dubte clàssic de qui comença.

Contingut

  1. La situació d'en Bruno
  2. git clone en la seva forma més simple
  3. Què fa realment git clone, pas a pas
  4. Protocols: HTTPS, SSH i ruta local
  5. Clonar en un directori amb un altre nom
  6. Clonar una branca concreta amb --branch
  7. Clons superficials amb --depth
  8. --single-branch i altres opcions útils
  9. init enfront de clone: la diferència conceptual
  10. Comprovacions després de clonar

  1. La situació d'en Bruno

El repositori de gestor-tasques està publicat al servidor intern de l'empresa. En Bruno té tres adreces possibles per accedir-hi:

https://git.exemple.cat/equip/gestor-tasques.git      (HTTPS)
[email protected]:equip/gestor-tasques.git          (SSH)
/Volumes/compartit/repos/gestor-tasques.git           (ruta local, disc compartit)

Les tres apunten al mateix repositori: un repositori bare —sense directori de treball, com vam veure al final de la lliçó anterior— que actua com a punt central de l'equip. Com hi va arribar el repositori de l'Ana i com es gestionen aquestes adreces és matèria del mòdul 4; aquí ens centrem en l'altra banda de l'operació: endur-se'l.

En Bruno ja té Git instal·lat i configurat amb la seva identitat, seguint el que vam veure al mòdul 1:

git config --global user.name
# → Bruno Salas
git config --global user.email
# → [email protected]

  1. git clone en la seva forma més simple

En Bruno se situa a la carpeta on desa els seus projectes i executa:

cd ~/Projectes
git clone https://git.exemple.cat/equip/gestor-tasques.git
Cloning into 'gestor-tasques'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 24 (delta 6), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (24/24), 4.21 KiB | 4.21 MiB/s, done.
Resolving deltas: 100% (6/6), done.

I ja està: en uns segons té el projecte complet.

cd gestor-tasques
ls -a
.  ..  .git  app.js  estils.css  index.html  README.md
git log --oneline
c5d9b1e (HEAD -> main, origin/main, origin/HEAD) 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

Aquí hi ha l'historial complet de l'Ana, inclòs el commit inicial que vam crear a la lliçó anterior i la confirmació recurrent "Afegeix l'esborrat de tasques al llistat" sobre app.js. En Bruno no ha rebut una foto del projecte: ha rebut el projecte i la seva memòria.

I el directori de treball està net des del primer moment:

git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

Desxifrant la sortida del clon

Les línies que apareixen durant la descàrrega no són soroll; descriuen el que fa el servidor:

Línia Què significa
Enumerating objects El servidor calcula quins objectes cal enviar
Counting objects Els compta i prepara l'enviament
Compressing objects Els comprimeix en un packfile per enviar menys bytes
Total 24 (delta 6) 24 objectes, dels quals 6 s'envien com a diferències respecte d'altres
Receiving objects Progrés de la descàrrega a la teva màquina
Resolving deltas El teu Git reconstrueix els objectes complets a partir de les diferències

Aquest (delta 6) connecta amb una cosa que vam esmentar a El Model de Dades de Git: conceptualment Git desa instantànies, però per emmagatzemar-les i transmetre-les fa servir packfiles que sí que comprimeixen uns objectes contra altres. És una optimització invisible: en acabar Resolving deltas, al disc d'en Bruno hi ha exactament els mateixos objectes que al de l'Ana.

  1. Què fa realment git clone, pas a pas

Un clon sembla un simple "baixar carpeta", però són cinc operacions encadenades. Entendre-les evita moltíssimes confusions posteriors.

graph TD
    A["1 · Crear el directori<br/>gestor-tasques/"] --> B["2 · Crear .git/ a dins<br/>(com un git init)"]
    B --> C["3 · Descarregar TOTS els objectes<br/>i referències de l'origen"]
    C --> D["4 · Registrar l'origen<br/>com a remot 'origin'"]
    D --> E["5 · Crear la branca local 'main'<br/>i bolcar els seus fitxers al<br/>directori de treball"]

Pas 1: crear el directori

Si no indiques cap altra cosa, Git fa servir l'últim segment de l'URL sense el sufix .git. De https://git.exemple.cat/equip/gestor-tasques.git en surt la carpeta gestor-tasques. Si aquesta carpeta ja existeix i no és buida, el clon falla:

fatal: destination path 'gestor-tasques' already exists and is not an empty directory.

És una protecció deliberada: git clone no sobreescriu mai feina existent.

Pas 2: inicialitzar el repositori

Internament, un clon comença fent l'equivalent a git init al directori destí. Per això el resultat té exactament la mateixa anatomia que vam estudiar ahir:

ls -F .git
branches/  config  description  FETCH_HEAD  HEAD  hooks/  index  info/  logs/  objects/  packed-refs  refs/

Hi apareixen alguns elements que en un git init pur no hi havia —index, logs/, packed-refs, FETCH_HEAD— senzillament perquè aquí sí que hi ha contingut: hi ha fitxers preparats, hi ha referències per empaquetar i hi ha hagut una operació de xarxa.

Pas 3: descarregar els objectes

Aquí passa el que és important. Git descarrega la base de dades d'objectes completa: tots els blobs, tots els trees, tots els commits i totes les etiquetes del repositori d'origen, juntament amb les seves referències.

Això és el que fa de Git un sistema distribuït, tal com vam veure a Què és Git?: després del clon, el portàtil d'en Bruno conté una còpia íntegra i funcional del projecte. Pot consultar l'historial, comparar versions de fa un any o crear confirmacions sense connexió a la xarxa. En un sistema centralitzat com SVN, gairebé qualsevol d'aquestes operacions exigiria parlar amb el servidor.

Ho podem verificar:

git count-objects -v
count: 0
size: 0
in-pack: 24
packed: 24
prune-packable: 0
garbage: 0
size-pack: 5

Els 24 objectes hi són, dins d'un packfile (in-pack: 24).

Pas 4: registrar el remot origin

El clon desa d'on va venir, amb el nom convencional origin:

git remote -v
origin	https://git.exemple.cat/equip/gestor-tasques.git (fetch)
origin	https://git.exemple.cat/equip/gestor-tasques.git (push)

I ho deixa escrit a la configuració local del repositori:

cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = https://git.exemple.cat/equip/gestor-tasques.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main

origin no és una paraula reservada de Git: és només el nom per defecte que clone posa al remot. El podries anomenar central, upstream o servidor. La convenció està tan assentada que convé respectar-la.

La secció [branch "main"] significa que la branca local main segueix origin/main. Gràcies a això git status et pot dir si vas per davant o per darrere del servidor. Tot això —remots, branques de seguiment, fetch, pull, push— és el contingut del mòdul 4; aquí n'hi ha prou de saber que el clon ho deixa configurat tot sol.

Pas 5: crear la branca local i bolcar els fitxers

Finalment, Git crea una branca local que correspon a la branca per defecte de l'origen (main), situa HEAD en ella i escriu al disc els fitxers d'aquesta confirmació, poblant alhora el directori de treball i l'àrea de preparació.

Aquest últim matís explica per què git status surt net tot just clonar: les tres zones —repositori, àrea de preparació i directori de treball— estan sincronitzades amb el mateix contingut.

  1. Protocols: HTTPS, SSH i ruta local

L'URL que passes a git clone determina com viatgen les dades. Aquests són els tres casos que trobaràs a la pràctica:

HTTPS SSH Ruta local
Forma https://host/grup/repo.git git@host:grup/repo.git /ruta/al/repo.git o file:///ruta
Autenticació Usuari + token d'accés Parell de claus pública/privada Permisos del sistema de fitxers
Port habitual 443 22
Travessa tallafocs Gairebé sempre De vegades bloquejat
Demana credencials en clonar Sí, llevat de repositori públic No, si la clau està carregada No
Comoditat diària Mitjana (necessita gestor de credencials) Alta, un cop configurada Màxima
Ús típic Primer contacte, CI, xarxes restrictives Feina diària d'un desenvolupador Còpies de seguretat, proves, discs compartits

HTTPS

És l'opció més universal perquè el port 443 està obert pràcticament a tot arreu. En clonar un repositori privat et demanarà credencials:

git clone https://git.exemple.cat/equip/gestor-tasques.git
Cloning into 'gestor-tasques'...
Username for 'https://git.exemple.cat': bruno.salas
Password for 'https://[email protected]':

Un avís important: a les plataformes modernes (GitHub, GitLab…) aquesta "contrasenya" no és la contrasenya del teu compte, sinó un token d'accés personal. Per no haver-lo de reintroduir cada vegada, serveix el credential.helper que vam configurar a Configuració Inicial.

SSH

Fixa't que la forma SSH abreujada no porta :// i fa servir dos punts per separar l'amfitrió de la ruta:

git clone [email protected]:equip/gestor-tasques.git

Es recolza en un parell de claus criptogràfiques: la pública es registra al servidor i la privada es queda a la teva màquina. Un cop configurat, clonar i treballar no torna a demanar contrasenya. És l'opció preferida per a la feina diària. La generació de claus i el seu registre s'expliquen a Autenticació amb Repositoris Remots.

Existeix també la forma llarga equivalent, que sí que porta :// i permet especificar port:

git clone ssh://[email protected]:2222/equip/gestor-tasques.git

Ruta local

Pots clonar d'una carpeta del disc mateix o d'un recurs muntat en xarxa:

git clone /Volumes/compartit/repos/gestor-tasques.git
git clone ~/copies/gestor-tasques.git copia-de-treball

És rapidíssim i no necessita ni xarxa ni credencials. Té una peculiaritat útil: quan origen i destí són al mateix sistema de fitxers, Git fa servir enllaços durs per als objectes en lloc de copiar-los, així que el clon gairebé no ocupa res. Si prefereixes una còpia realment independent:

git clone --no-hardlinks /Volumes/compartit/repos/gestor-tasques.git

I si escrius la ruta amb el prefix file://, Git fa servir el mateix mecanisme de transferència que faria servir amb un servidor remot, cosa que resulta pràctica per fer proves:

git clone file:///Volumes/compartit/repos/gestor-tasques.git

Compte amb clonar d'un repositori no bare. Es pot clonar d'un repositori normal (per exemple, directament de ~/projectes/gestor-tasques de l'Ana), i funciona: obtens tot l'historial. Però només obtens el que està confirmat: els canvis que l'Ana tingui sense confirmar al seu directori de treball o a la seva àrea de preparació no viatgen. És una font de sorpreses: "he clonat el teu repo i hi falta el teu últim canvi" gairebé sempre significa "no l'havies confirmat".

  1. Clonar en un directori amb un altre nom

N'hi ha prou d'afegir el nom desitjat com a segon argument:

git clone https://git.exemple.cat/equip/gestor-tasques.git gestor
Cloning into 'gestor'...

El repositori és idèntic; només canvia la carpeta que el conté. És útil en tres situacions:

  • Evitar col·lisions: ja tens una carpeta gestor-tasques d'un altre projecte.
  • Tenir dues còpies del mateix repositori, per exemple una per treballar i una altra per consultar una versió antiga sense tocar la primera. (Per a aquest cas concret existeix una eina específica, git worktree, que veuràs al mòdul 6.)
  • Noms poc descriptius: si el repositori es diu web, potser prefereixes web-client-acme.

Si vols clonar al directori actual i no en un de nou, fes servir . com a destí. El directori ha de ser buit:

mkdir gestor-tasques && cd gestor-tasques
git clone https://git.exemple.cat/equip/gestor-tasques.git .

  1. Clonar una branca concreta amb --branch

Per defecte, el clon et deixa situat a la branca per defecte de l'origen (main). Amb --branch (o -b) en tries una altra:

git clone --branch desenvolupament https://git.exemple.cat/equip/gestor-tasques.git
git branch --show-current
desenvolupament

Dues precisions importants:

  1. Es descarrega tot el repositori igualment. --branch no filtra el que arriba; només decideix en quina branca et deixa. Les altres continuen allà, accessibles.
  2. També accepta etiquetes. Si li passes un nom d'etiqueta, obtindràs el contingut exacte d'aquella versió, però en estat detached HEAD (no seràs a cap branca):
git clone --branch v1.0 https://git.exemple.cat/equip/gestor-tasques.git gestor-v1
Note: switching to 'v1.0'.
You are in 'detached HEAD' state...

És perfectament vàlid per inspeccionar una versió publicada. Què significa exactament aquest estat i com sortir-ne correspon a Entenent les Branques i a Etiquetant Confirmacions.

  1. Clons superficials amb --depth

En un projecte amb anys d'història, clonar-lo sencer pot significar descarregar centenars de megabytes que potser no necessites. --depth limita quantes confirmacions es porten:

git clone --depth 1 https://git.exemple.cat/equip/gestor-tasques.git
Cloning into 'gestor-tasques'...
remote: Enumerating objects: 6, done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), 1.83 KiB | 1.83 MiB/s, done.

Compara-ho amb el clon complet de l'apartat 2: 6 objectes en lloc de 24. Només ha arribat l'última confirmació.

git log --oneline
c5d9b1e (grafted, HEAD -> main, origin/main) Documenta la instal·lació al README

La paraula grafted ("empeltat") marca el punt on l'historial es talla artificialment. Aquest commit sembla no tenir pare, encara que al repositori original sí que en tingui.

Què es perd amb un clon superficial

Operació Clon complet --depth 1
Veure els fitxers actuals
Compilar / executar el projecte
Crear confirmacions noves
git log complet No, només l'última
git blame fiable No
git bisect per buscar una fallada No
Comparar amb versions antigues No
Mida de descàrrega 100 % Mínima

Quan fer-lo servir i quan no

Sí:

  • Integració contínua. Un servidor de CI compila i descarta la còpia; l'historial li sobra. És, de bon tros, l'ús més comú.
  • Contenidors i imatges de desplegament, on cada megabyte compta.
  • Consulta puntual d'un projecte enorme del qual només vols veure el codi d'avui.

No:

  • La teva còpia de treball diària. Et quedes sense blame, sense bisect i sense poder comparar amb el passat, que són tres de les raons per fer servir Git.

Convertir un clon superficial en complet

Si te'n penedeixes, no cal tornar a clonar:

git fetch --unshallow

O portar-te més profunditat de la que tens:

git fetch --deepen 50

Totes dues ordres pertanyen al mòdul 4; les esmentem aquí perquè sàpigues que la decisió és reversible.

Nota moderna. En Git recent existeixen els clons parcials (--filter=blob:none), que descarreguen tot el graf de commits però porten el contingut dels fitxers només quan cal. Conserven log, blame i bisect i solen ser millor opció que --depth per a repositoris grans. Ho veurem a Escalant Git per a Projectes Grans.

  1. --single-branch i altres opcions útils

--single-branch descarrega únicament la branca indicada, ignorant les altres:

git clone --single-branch --branch main https://git.exemple.cat/equip/gestor-tasques.git

A diferència de --depth, conserva tot l'historial d'aquesta branca; el que evita és portar branques que no t'interessen. En un repositori amb dues-centes branques de treball, la diferència es nota.

Nota important: --depth implica --single-branch automàticament, llevat que hi afegeixis --no-single-branch.

Un resum de les opcions més freqüents:

Opció Efecte Ús típic
-b, --branch <nom> Situa en aquesta branca o etiqueta Treballar a desenvolupament des del minut u
--depth <n> Només les n últimes confirmacions Integració contínua
--single-branch Només una branca, amb tot el seu historial Repositoris amb moltes branques
--no-checkout, -n Descarrega però no bolca els fitxers Preparar el repositori abans de poblar-lo
--bare Clon sense directori de treball Crear una rèplica per servir
--mirror Com --bare, però rèplica exacta de totes les referències Còpies de seguretat, migracions
--recurse-submodules Clona també els submòduls Projectes amb submòduls
--origin <nom>, -o Anomena el remot d'una altra manera Quan origin ja significa una altra cosa
--quiet, -q Sense barres de progrés Scripts

Un parell d'exemples comentats:

# Còpia de seguretat completa del repositori de l'equip
git clone --mirror https://git.exemple.cat/equip/gestor-tasques.git copia-gestor.git

Això crea un repositori bare amb totes les referències de l'origen, no només les branques. És la manera habitual de migrar un repositori d'un servidor a un altre.

# Clonar anomenant el remot "central" en lloc de "origin"
git clone --origin central https://git.exemple.cat/equip/gestor-tasques.git
git remote -v
# → central	https://git.exemple.cat/equip/gestor-tasques.git (fetch)
# → central	https://git.exemple.cat/equip/gestor-tasques.git (push)

  1. init enfront de clone: la diferència conceptual

És el dubte més habitual en començar, i es resol amb una pregunta: ja existeix el projecte en algun lloc?

git init git clone
Punt de partida Res o una carpeta amb fitxers teus Un repositori que ja existeix
Historial resultant Buit: zero confirmacions Complet, idèntic al de l'origen
Remot configurat Cap origin, automàticament
Branca inicial La d'init.defaultBranch, sense existir encara La branca per defecte de l'origen, ja creada
Directori de treball El que ja tinguessis Poblat amb els fitxers de l'origen
Necessita xarxa No Sí (llevat de ruta local)
Frase que ho resumeix "Començo un projecte" "M'uneixo a un projecte"

L'Ana va fer servir init perquè el projecte naixia amb ella. En Bruno fa servir clone perquè el projecte ja existia. Cada persona de l'equip farà clone una vegada per projecte i per màquina; init s'executa una sola vegada en la vida d'un projecte.

graph TD
    Q{"El projecte ja existeix<br/>en un repositori Git?"}
    Q -->|No| I["git init<br/>Historial buit<br/>Sense remot"]
    Q -->|Sí| C["git clone URL<br/>Historial complet<br/>Remot 'origin' llest"]
    I --> P["Primer commit"]
    C --> W["Començar a treballar<br/>directament"]

Un error freqüent mereix menció a part: fer git init en una carpeta buida amb la intenció de "baixar-se" un projecte que ja existeix, i després intentar connectar-lo a mà. És possible —afegint el remot i descarregant, com veurem al mòdul 4— però és fer tres passos on git clone en fa un, i és fàcil deixar-ho mal configurat. Si el projecte ja existeix, clona.

  1. Comprovacions després de clonar

Aquestes quatre comprovacions triguen deu segons i eviten malentesos:

# 1. D'on va venir aquest repositori?
git remote -v
# → origin	https://git.exemple.cat/equip/gestor-tasques.git (fetch)
# → origin	https://git.exemple.cat/equip/gestor-tasques.git (push)

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

# 3. Tinc l'historial complet o és un clon superficial?
git rev-parse --is-shallow-repository
# → false

# 4. Quantes confirmacions he rebut?
git rev-list --count HEAD
# → 4

I una cinquena que és la més important en un equip amb perfils condicionals (includeIf), com el que vam muntar a Configurant Git:

git config user.email
# → [email protected]

Comprovar-ho abans de la primera confirmació és molt més barat que corregir l'autoria després, cosa que exigeix reescriure l'historial.

Errors Habituals i Consells

  • Clonar dins d'un repositori existent. Si executes git clone sense fixar-t'hi i ets dins d'un altre projecte, acabes amb un repositori imbricat que confon Git i els teus companys. Comprova-ho abans amb pwd, o amb git rev-parse --show-toplevel.
  • Fer servir --depth 1 a la còpia de treball diària. Estalvies uns segons una vegada i perds blame, bisect i totes les comparacions històriques durant mesos. Reserva-ho per a CI i contenidors.
  • Confondre l'URL SSH amb la d'HTTPS. git@host:grup/repo.git és SSH (sense ://, amb dos punts); https://host/grup/repo.git és HTTPS. Si copies la d'SSH sense tenir claus configurades, el clon fallarà amb Permission denied (publickey).
  • Creure que clonar copia també la feina sense confirmar. El clon porta només el que està confirmat. Si hi falta alguna cosa, gairebé sempre és perquè no es va confirmar.
  • Esperar que el .gitignore faci desaparèixer fitxers en clonar. El clon reprodueix el que hi ha a l'historial. Si un fitxer indesitjat es va confirmar en el seu dia, arribarà igualment; ignorar-lo ara no el treu del passat.
  • Clonar un projecte enorme per HTTPS en una xarxa lenta i donar-lo per penjat. Fes servir git clone --progress o afegeix-hi --depth si de debò no necessites l'historial.
  • Consell: si el clon falla a mitges, esborra la carpeta a mig crear abans de reintentar-ho; si no, el segon intent fallarà amb destination path already exists.
  • Consell: just després de clonar, executa git log --oneline -5 i fes un cop d'ull al README. Són dos minuts que t'estalvien preguntes a l'equip.

Exercicis

Exercici 1: Simular el clon d'en Bruno amb una ruta local

Sense servidor ni xarxa, reprodueix l'escenari complet. Partint d'un repositori amb dues confirmacions que simuli el de l'Ana:

  1. Crea ~/practica/ana/gestor-tasques amb un README.md i un app.js, i inicialitza'l amb dues confirmacions.
  2. Crea a partir d'ell un repositori bare a ~/practica/servidor/gestor-tasques.git que faci de punt central.
  3. Clona'l a ~/practica/bruno/gestor-tasques, simulant en Bruno.
  4. Demostra amb ordres que en Bruno té: les dues confirmacions, el remot origin apuntant al bare, i la branca main seguint origin/main.

Exercici 2: Comparar un clon complet amb un de superficial

Fent servir el repositori bare de l'exercici anterior (amplia'l abans a cinc confirmacions perquè es noti la diferència), fes dos clons: un de complet i un altre amb --depth 1. Després:

  1. Compara el nombre d'objectes de cadascun.
  2. Compara la sortida de git log --oneline.
  3. Intenta executar git log sobre un fitxer concret en tots dos i explica'n la diferència.
  4. Converteix el clon superficial en complet i comprova que ara es comporta igual que l'altre.

Exercici 3: Triar l'ordre correcta

Per a cada situació, indica quina ordre exacta faries servir i justifica breument per què. Hi ha un parany deliberat a la llista.

  1. La Carla comença avui i necessita gestor-tasques al seu Windows 11, amb tot l'historial, per treballar-hi a diari.
  2. El servidor d'integració contínua ha de compilar l'última versió de main a cada canvi, tan de pressa com sigui possible.
  3. L'Ana vol començar un projecte nou, informes-mensuals, que encara no existeix enlloc.
  4. En Bruno necessita revisar com era estils.css a la versió etiquetada v1.0, sense deixar de treballar a la seva còpia actual.
  5. L'equip migra de servidor i cal endur-se el repositori íntegre, amb totes les branques i etiquetes.
  6. La Carla ja té la carpeta gestor-tasques amb el projecte baixat en .zip d'un company i vol "connectar-la" al repositori de l'equip.

Solucions

Solució a l'Exercici 1

Pas 1 — el repositori de l'Ana:

mkdir -p ~/practica/ana/gestor-tasques
cd ~/practica/ana/gestor-tasques
git init
echo "# Gestor de Tasques" > README.md
git add README.md
git commit -m "Estructura inicial del gestor de tasques"
echo "const tasques = [];" > app.js
git add app.js
git commit -m "Afegeix l'esquelet de la lògica de tasques"
git log --oneline
7d2f9a1 (HEAD -> main) Afegeix l'esquelet de la lògica de tasques
1a4c8d6 Estructura inicial del gestor de tasques

Pas 2 — el repositori central bare:

mkdir -p ~/practica/servidor
cd ~/practica/servidor
git clone --bare ~/practica/ana/gestor-tasques gestor-tasques.git
Cloning into bare repository 'gestor-tasques.git'...
done.

--bare crea la rèplica sense directori de treball, que és exactament el que ha de ser un repositori central:

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

Pas 3 — el clon d'en Bruno:

mkdir -p ~/practica/bruno
cd ~/practica/bruno
git clone ~/practica/servidor/gestor-tasques.git
cd gestor-tasques

Pas 4 — les tres demostracions:

# Les dues confirmacions, amb els mateixos hashos que al repo de l'Ana
git log --oneline
# → 7d2f9a1 (HEAD -> main, origin/main, origin/HEAD) Afegeix l'esquelet de la lògica de tasques
# → 1a4c8d6 Estructura inicial del gestor de tasques

# El remot origin apunta al bare
git remote -v
# → origin	/home/ana/practica/servidor/gestor-tasques.git (fetch)
# → origin	/home/ana/practica/servidor/gestor-tasques.git (push)

# La branca main segueix origin/main
git status -sb
# → ## main...origin/main

git config branch.main.remote     # → origin
git config branch.main.merge      # → refs/heads/main

Que els hashos coincideixin exactament amb els del repositori de l'Ana no és casualitat: com vam veure a El Model de Dades de Git, el hash es deriva del contingut, així que copiar objectes entre repositoris preserva els identificadors. Aquesta és la base perquè Git pugui sincronitzar màquines diferents sense ambigüitat.

Solució a l'Exercici 2

Ampliem primer l'historial de l'Ana i el portem al bare (la mecànica d'enviar canvis és del mòdul 4, així que aquí ho resolem tornant a clonar):

cd ~/practica/ana/gestor-tasques
for n in 3 4 5; do echo "linia $n" >> app.js; git commit -am "Canvi número $n"; done
rm -rf ~/practica/servidor/gestor-tasques.git
git clone --bare . ~/practica/servidor/gestor-tasques.git

Els dos clons:

cd ~/practica
git clone ~/practica/servidor/gestor-tasques.git complet
git clone --depth 1 file://$HOME/practica/servidor/gestor-tasques.git superficial

(Es fa servir file:// perquè --depth no té efecte sobre una ruta local directa: Git optimitza aquest cas copiant o enllaçant els objectes sencers.)

1. Nombre d'objectes:

git -C complet count-objects -v | grep in-pack
# → in-pack: 17

git -C superficial count-objects -v | grep in-pack
# → in-pack: 4

2. L'historial:

git -C complet log --oneline
# → e9a2c5f (HEAD -> main, origin/main, origin/HEAD) Canvi número 5
# → b3d7f1c Canvi número 4
# → 5a8e2b9 Canvi número 3
# → 7d2f9a1 Afegeix l'esquelet de la lògica de tasques
# → 1a4c8d6 Estructura inicial del gestor de tasques

git -C superficial log --oneline
# → e9a2c5f (grafted, HEAD -> main, origin/main) Canvi número 5

3. Historial d'un fitxer:

git -C complet log --oneline -- app.js
# → e9a2c5f Canvi número 5
# → b3d7f1c Canvi número 4
# → 5a8e2b9 Canvi número 3
# → 7d2f9a1 Afegeix l'esquelet de la lògica de tasques

git -C superficial log --oneline -- app.js
# → e9a2c5f Canvi número 5

La diferència no és cosmètica: al clon superficial el fitxer sembla haver nascut complet a l'última confirmació. Qualsevol investigació sobre quan es va introduir una línia —git log, git blame o git bisect— donarà una resposta falsa. Per això --depth serveix per compilar, no per investigar.

4. Convertir-lo en complet:

cd ~/practica/superficial
git rev-parse --is-shallow-repository      # → true
git fetch --unshallow
git rev-parse --is-shallow-repository      # → false
git log --oneline | wc -l                  # → 5

Ja no apareix grafted i l'historial coincideix amb el del clon complet.

Solució a l'Exercici 3

1. La Carla s'incorpora:

git clone [email protected]:equip/gestor-tasques.git

Clon complet i normal. És la seva còpia de treball diària, així que res de --depth: necessitarà blame i historial. SSH si té claus configurades; HTTPS si encara no.

2. Servidor d'integració contínua:

git clone --depth 1 --branch main https://git.exemple.cat/equip/gestor-tasques.git

És el cas de manual per al clon superficial: compila i descarta, l'historial no aporta res i la descàrrega es minimitza. HTTPS amb token és l'habitual en CI perquè evita gestionar claus SSH.

3. Projecte nou:

cd ~/projectes
git init informes-mensuals

No hi ha res a clonar: el projecte neix aquí. git init <nom> crea a més la carpeta.

4. Consultar la versió v1.0 sense tocar la feina actual:

git clone --branch v1.0 https://git.exemple.cat/equip/gestor-tasques.git ~/consulta-v1

Un segon clon en una altra carpeta i amb un altre nom deixa la seva còpia de treball intacta. Quedarà en detached HEAD, que per consultar és correcte. (Solució alternativa i més elegant, que veurà al mòdul 6: git worktree add.)

5. Migració de servidor:

git clone --mirror https://git.exemple.cat/equip/gestor-tasques.git gestor-tasques.git

--mirror és l'opció correcta, no --bare a seques: replica totes les referències —branques, etiquetes i referències remotes— i no només les branques locals. És la manera estàndard de moure un repositori íntegre entre servidors.

6. El parany. Aquí no cal clonar sobre la carpeta existent, i de fet Git no ho permetria: git clone exigeix un directori buit o inexistent. Però el problema de fons és un altre: la carpeta de la Carla ve d'un .zip, així que no té historial ni cap relació amb el repositori de l'equip. Connectar-la a mà només generaria conflictes i confusió.

La resposta correcta és descartar aquesta carpeta i clonar de debò:

mv gestor-tasques gestor-tasques-zip-antic     # per si de cas
git clone [email protected]:equip/gestor-tasques.git

Si la Carla hagués fet canvis a la còpia del .zip, es copien a mà al clon acabat de fer i es confirmen allà com a canvis normals. La regla general: una carpeta baixada en .zip no és un repositori i no es converteix en un amb git init; per unir-se a un projecte existent es clona.

Conclusió

En Bruno ja forma part del projecte. En aquesta lliçó hem vist que:

  • git clone fa cinc coses, no una: crea el directori, l'inicialitza, descarrega tota la base de dades d'objectes, registra l'origen com a remot origin i crea la branca local bolcant-ne els fitxers al directori de treball.
  • El clon porta l'historial complet, i aquesta és l'essència del model distribuït: en Bruno pot consultar, comparar i confirmar sense xarxa.
  • Hi ha tres protocols habituals: HTTPS (universal, amb token), SSH (còmode per al dia a dia, amb claus) i ruta local (instantani, per a còpies i proves). Es distingeixen a simple vista per la forma de l'URL.
  • Pots triar el nom del directori, la branca de destí amb --branch i la profunditat de l'historial amb --depth.
  • Els clons superficials són excel·lents per a CI i pèssims per treballar, perquè trenquen log, blame i bisect. La decisió és reversible amb git fetch --unshallow.
  • init i clone responen a preguntes diferents: init quan el projecte neix amb tu, clone quan t'uneixes a un que ja existeix.
  • El clon només porta el que està confirmat. El que estigui sense confirmar a l'origen no viatja.

L'Ana i en Bruno ja tenen cadascun el seu repositori: una el va crear, l'altre el va clonar. A partir d'aquí, tots dos fan exactament el mateix cada dia: editar fitxers, decidir quins canvis agrupar i registrar-los a l'historial.

Aquest cicle —editar, preparar, confirmar— és el batec de Git i el tema de la lliçó següent, Flux de Treball Bàsic de Git. Allà posarem en moviment les tres zones que coneixes des del mòdul 1, seguirem el cicle de vida complet d'un fitxer des que Git no el coneix fins que queda confirmat, i aprendrem a llegir git status —en la seva forma llarga i en l'abreujada— com la brúixola que et diu, en tot moment, on ets.

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