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
- La situació d'en Bruno
git cloneen la seva forma més simple- Què fa realment
git clone, pas a pas - Protocols: HTTPS, SSH i ruta local
- Clonar en un directori amb un altre nom
- Clonar una branca concreta amb
--branch - Clons superficials amb
--depth --single-branchi altres opcions útilsinitenfront declone: la diferència conceptual- Comprovacions després de clonar
- 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]
git clone en la seva forma més simple
git clone en la seva forma més simpleEn Bruno se situa a la carpeta on desa els seus projectes i executa:
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.
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:
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.
- Què fa realment
git clone, pas a pas
git clone, pas a pasUn 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:
É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:
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:
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:
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:
[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/mainorigin 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.
- 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:
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.gitEs 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.gitRuta 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:
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:
Compte amb clonar d'un repositori no bare. Es pot clonar d'un repositori normal (per exemple, directament de
~/projectes/gestor-tasquesde 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".
- Clonar en un directori amb un altre nom
N'hi ha prou d'afegir el nom desitjat com a segon argument:
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-tasquesd'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 prefereixesweb-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 .
- Clonar una branca concreta amb
--branch
--branchPer defecte, el clon et deixa situat a la branca per defecte de l'origen (main). Amb --branch (o -b) en tries una altra:
Dues precisions importants:
- Es descarrega tot el repositori igualment.
--branchno filtra el que arriba; només decideix en quina branca et deixa. Les altres continuen allà, accessibles. - 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):
É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.
- Clons superficials amb
--depth
--depthEn 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:
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ó.
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 | Sí | Sí |
| Compilar / executar el projecte | Sí | Sí |
| Crear confirmacions noves | Sí | Sí |
git log complet |
Sí | No, només l'última |
git blame fiable |
Sí | No |
git bisect per buscar una fallada |
Sí | No |
| Comparar amb versions antigues | Sí | 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, sensebisecti 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:
O portar-te més profunditat de la que tens:
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. Conservenlog,blameibisecti solen ser millor opció que--depthper a repositoris grans. Ho veurem a Escalant Git per a Projectes Grans.
--single-branch i altres opcions útils
--single-branch i altres opcions útils--single-branch descarrega únicament la branca indicada, ignorant les altres:
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.gitAixò 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)
init enfront de clone: la diferència conceptual
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.
- 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
# → 4I 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 clonesense 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 ambpwd, o ambgit rev-parse --show-toplevel. - Fer servir
--depth 1a la còpia de treball diària. Estalvies uns segons una vegada i perdsblame,bisecti 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à ambPermission 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
.gitignorefaci 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 --progresso afegeix-hi--depthsi 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 -5i 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:
- Crea
~/practica/ana/gestor-tasquesamb unREADME.mdi unapp.js, i inicialitza'l amb dues confirmacions. - Crea a partir d'ell un repositori bare a
~/practica/servidor/gestor-tasques.gitque faci de punt central. - Clona'l a
~/practica/bruno/gestor-tasques, simulant en Bruno. - Demostra amb ordres que en Bruno té: les dues confirmacions, el remot
originapuntant al bare, i la brancamainseguintorigin/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:
- Compara el nombre d'objectes de cadascun.
- Compara la sortida de
git log --oneline. - Intenta executar
git logsobre un fitxer concret en tots dos i explica'n la diferència. - 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.
- La Carla comença avui i necessita
gestor-tasquesal seu Windows 11, amb tot l'historial, per treballar-hi a diari. - El servidor d'integració contínua ha de compilar l'última versió de
maina cada canvi, tan de pressa com sigui possible. - L'Ana vol començar un projecte nou,
informes-mensuals, que encara no existeix enlloc. - En Bruno necessita revisar com era
estils.cssa la versió etiquetadav1.0, sense deixar de treballar a la seva còpia actual. - L'equip migra de servidor i cal endur-se el repositori íntegre, amb totes les branques i etiquetes.
- La Carla ja té la carpeta
gestor-tasquesamb el projecte baixat en.zipd'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 --oneline7d2f9a1 (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--bare crea la rèplica sense directori de treball, que és exactament el que ha de ser un repositori central:
Pas 3 — el clon d'en Bruno:
mkdir -p ~/practica/bruno
cd ~/practica/bruno
git clone ~/practica/servidor/gestor-tasques.git
cd gestor-tasquesPas 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/mainQue 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.gitEls 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: 42. 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 53. 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 5La 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 # → 5Ja 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.gitClon 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:
É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:
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:
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:
--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.gitSi 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 clonefa cinc coses, no una: crea el directori, l'inicialitza, descarrega tota la base de dades d'objectes, registra l'origen com a remotorigini 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
--branchi 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,blameibisect. La decisió és reversible ambgit fetch --unshallow. initicloneresponen a preguntes diferents:initquan el projecte neix amb tu,clonequan 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
- Què és Git?
- Instal·lant Git
- Terminologia Bàsica de Git
- El Model de Dades de Git
- Configurant Git
- Configuració Inicial
Mòdul 2: Operacions Bàsiques de Git
- Creant un Repositori
- Clonant un Repositori
- Flux de Treball Bàsic de Git
- Preparant i Confirmant Canvis
- Inspeccionant Canvis amb git diff
- Visualitzant l'Historial de Confirmacions
Mòdul 3: Branques i Fusió
- Entenent les Branques
- Creant i Canviant Branques
- Fusionant Branques
- Estratègies de Fusió
- Resolent Conflictes de Fusió
- Gestió de Branques
Mòdul 4: Treballant amb Repositoris Remots
- Entenent els Repositoris Remots
- Afegint un Repositori Remot
- Autenticació amb Repositoris Remots
- Obtenint i Baixant Canvis
- Enviant Canvis
- Rastrejant Branques
Mòdul 5: Operacions Avançades de Git
- Rebase
- Rebase Interactiu
- Cherry-Picking de Confirmacions
- Desant Canvis Temporals
- Etiquetant Confirmacions
- Revertint Confirmacions
Mòdul 6: Eines i Tècniques de Git
- Usant Git Hooks
- Git Bisect
- Git Blame
- Git Log i Àlies
- Submòduls de Git
- Múltiples Còpies de Treball amb git worktree
Mòdul 7: Estratègies de Col·laboració i Flux de Treball
- Forks i Pull Requests
- Revisions de Codi amb Git
- Flux de Treball Git Flow
- GitHub Flow
- Trunk Based Development
- Integració Contínua amb Git
Mòdul 8: Bones Pràctiques i Consells de Git
- Escrivint Bons Missatges de Confirmació
- Mantenint un Historial Net
- Ignorant Fitxers amb .gitignore
- Atributs de Fitxer amb .gitattributes
- Bones Pràctiques de Seguretat
- Consells de Rendiment
Mòdul 9: Resolució de Problemes i Depuració
- Problemes Habituals de Git
- Desfent Canvis
- Resolent Divergències amb el Remot
- Recuperant Confirmacions Perdudes
- Tractant amb Repositoris Corruptes
- Tècniques Avançades de Depuració
