A la lliçó anterior vam recórrer quatre projectes molt diferents i en tots quatre va aparèixer el mateix: Git no treballa mai sol. Hi sortien llistes de correu, plataformes de propostes, sistemes de compilació, canonades d'integració i eines de seguiment. Git és el motor, però l'experiència diària de fer-lo servir la defineix tot el que hi ha al voltant.
Aquesta lliçó tracta d'aquesta capa. No d'ordres noves —tret d'un parell de peces que faltaven—, sinó de com encaixa Git en un lloc de treball real: l'editor, el terminal, el sistema de tiquets, els linters, la plataforma de revisió. I d'on és el risc, que no és tècnic sinó de comprensió.
Perquè hi ha un patró que es repeteix a tots els equips: algú porta dos anys fent servir Git des d'un botó del seu editor, tot va bé, i el dia que alguna cosa es torça descobreix que no sap què feia aquell botó. Aquell «Sincronitza» que ho resolia tot era git pull --rebase seguit de git push, i ara hi ha disset commits reescrits, una branca publicada divergent i cap idea de per on començar.
Tu ja saps sortir d'això (mòdul 9 sencer). El que farem aquí és fer servir les eines sense renunciar a entendre-les: aprofitar el que aporten de debò, saber quina ordre executen per sota i tenir clar què convé continuar fent a mà.
Contingut
- La regla de fons: l'eina no substitueix el model mental
- Editors i IDE: què aporten de debò
- Què convé continuar fent al terminal
- Clients gràfics i visors d'historial
- El terminal com a entorn de Git: prompt i autocompleció
- Sistemes de tiquets: tancant la convenció
GT-NNN - Eines de qualitat: linters, formatadors i
.editorconfig - Revisió i anàlisi: comprovacions d'estat
format-patch,amirequest-pullcom a pont entre mons- Com triar què automatitzar
- La regla de fons: l'eina no substitueix el model mental
Abans de res, la regla que ordena tota la lliçó:
Tota eina que integra Git acaba executant ordres de Git. Si saps quina ordre executa, l'eina t'estalvia temps. Si no ho saps, l'eina t'estalvia temps fins al dia que falla, i llavors et costa molt més del que t'havia estalviat.
No és un argument contra les interfícies gràfiques. És un argument a favor de saber llegir el que fan. Gairebé totes ofereixen una consola o un registre on mostren les ordres executades: mirar-la les primeres setmanes és la millor inversió d'aprenentatge que existeix.
I hi ha una asimetria important. Les eines són excel·lents en allò visual i repetitiu:
- Veure diferències amb colors, per paraules, costat per costat.
- Resoldre un conflicte amb tres plafons a la pantalla.
- Preparar canvis per fragments amb el ratolí.
- Veure el graf de commits dibuixat.
- Veure qui va escriure cada línia sense sortir del fitxer.
I són dolentes —o directament perilloses— en allò conceptual i irreversible:
- Qualsevol cosa que reescrigui l'historial.
- Resoldre una divergència amb el remot.
- Recuperar-se d'un error.
- Qualsevol operació sobre la qual vulguis entendre exactament què va passar.
La regla pràctica que en surt, i que és el resum de tot el mòdul:
Fes servir la interfície per mirar. Fes servir el terminal per decidir.
- Editors i IDE: què aporten de debò
Els editors moderns porten integració amb Git de sèrie. El que ve a continuació és què val la pena de debò, ordenat per rendibilitat.
Diferències visuals dins del mateix editor
L'editor marca al marge les línies afegides, modificades i esborrades respecte de HEAD, i permet veure la versió anterior d'un cop d'ull. Equival a git diff (lliçó 02-05) però sense canviar de context: veus el canvi dins del fitxer que estàs editant, amb el ressaltat de sintaxi del llenguatge.
És probablement la integració més valuosa que existeix, perquè canvia un hàbit: en lloc de revisar els canvis al final, els veus mentre treballes.
El que aporta: context immediat, diferència per paraules dins d'una línia, revertir un fragment concret amb un clic.
El que no substitueix: git diff --staged abans de confirmar. Continua sent l'últim control de qualitat, i convé fer-lo amb la vista completa.
Resolució de conflictes amb tres plafons
Quan hi ha un conflicte (lliçó 03-05), un bon editor mostra tres versions: la teva, la de l'altra branca i la base comuna. Poder veure la base és el que marca la diferència, perquè un conflicte només s'entén sabent de què partien els dos costats.
Això es pot configurar perquè Git l'invoqui directament:
# Registrar una eina de fusió
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
# No deixar fitxers .orig escampats pel disc
git config --global mergetool.keepBackup false
# Fer-la servir quan hi hagi conflicte
git mergetoolI l'equivalent per veure diferències:
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
git config --global difftool.prompt false
git difftool HEAD~1Un ajust que convé activar sempre, i que ja vam veure a la lliçó 03-05:
Amb zdiff3, els marcadors de conflicte inclouen la versió base entre ||||||| i =======, no només els dos costats. És la mateixa informació que donen els tres plafons, però al fitxer, i serveix tant si resols a l'editor com si ho fas a mà.
blame en línia
L'editor mostra al final de cada línia qui la va escriure, quan i amb quin missatge de commit. És git blame (lliçó 06-03) convertit en informació ambiental.
La seva virtut és que elimina la fricció de preguntar-se el perquè. Quan llegir el motiu d'una línia costa zero, es llegeix; quan costa una ordre i un canvi de finestra, no es llegeix.
El seu perill és el mateix que ja vam discutir: el blame et dona l'última persona que va tocar la línia, que moltes vegades és qui la va reindentar. Quan el resultat no tingui sentit, cal anar al terminal:
# Ignorar canvis d'espaiat i moviments de codi
git blame -w -M -C app.js
# Ignorar els commits de reformatatge massiu llistats en un fitxer
git blame --ignore-revs-file .git-blame-ignore-revs app.jsAquest fitxer .git-blame-ignore-revs a l'arrel del repositori és una llista de hashos de commits purament cosmètics:
# Reformatatge global amb el nou formatador (GT-198) 7c4d9e2f1a3b5c6d8e0f2a4b6c8d0e2f4a6b8c0d # Migració de cometes simples a dobles (GT-203) 2f8a1c4e6b9d0f3a5c7e9b1d3f5a7c9e1b3d5f7a
I es pot deixar actiu de manera permanent:
Els editors respecten aquesta configuració, així que el blame en línia deixa de mentir. És un ajust de dos minuts que millora la vida de tot l'equip.
Preparació per fragments amb el ratolí
git add -p (lliçó 02-04) és una de les eines més útils del curs i una de les més incòmodes de fer servir: cal decidir y/n/s/e sobre fragments que de vegades s'han de partir a mà. En un editor, seleccionar les línies que van a l'índex és qüestió de clics, i partir un fragment és trivial.
Aquí la interfície gràfica guanya amb claredat. Si l'e de l'add -p (editar el fragment a mà en format diff) et resulta hostil, aquesta és la seva alternativa raonable.
La resta: útil però secundari
- Historial del fitxer:
git log --follow -p fitxer, amb navegació còmoda. - Llista de branques i canvi entre elles: còmode, però convé saber que l'editor pot estar executant
git switchogit checkoutamb matisos diferents. - Desament temporal des del menú: equival a
git stash push, gairebé mai amb missatge. Un desament temporal sense missatge és un desament temporal que d'aquí a tres dies no sabràs què conté (lliçó 05-04).
Taula de correspondències
Útil per saber sempre què hi ha sota el botó:
| El que veus a l'editor | L'ordre de sota | Compte amb |
|---|---|---|
| «Sincronitza els canvis» | git pull (+ --rebase segons config) i després git push |
Pot reescriure els teus commits sense avisar |
| «Publica la branca» | git push -u origin <branca> |
Res, és segur |
| «Confirma» | git commit (a vegades amb -a implícit) |
El -a implícit confirma coses que no volies |
| «Confirma i envia» | git commit + git push |
Confirmar i publicar en un sol gest: sense marxa enrere còmoda |
| «Descarta els canvis» | git restore <fitxer> |
Irreversible: no hi ha reflog per als canvis sense confirmar |
| «Desfés l'últim commit» | git reset --soft HEAD~1 (normalment) |
Comprova si és --soft, --mixed o --hard |
| «Actualitza la branca» | git pull o git fetch + git merge/rebase |
Segons la config, produeix fusions o reescriu |
| «Resol a l'editor» | git mergetool o edició directa |
Recorda fer git add del fitxer resolt |
El més perillós de la taula és el primer. «Sincronitza» és un botó que fa dues operacions de xarxa, una de les quals pot reordenar el teu historial local segons un ajust global que potser vas posar fa un any. Val la pena mirar una vegada què fa exactament:
- Què convé continuar fent al terminal
L'altra meitat de la regla. Aquestes operacions convé fer-les escrivint l'ordre, i no per purisme:
| Operació | Per què al terminal |
|---|---|
Reescriure l'historial (rebase -i, commit --amend, filter-repo) |
Necessites veure exactament quins commits es toquen. La interfície amaga el pla. |
| Resoldre divergències amb el remot (09-03) | Requereix decidir entre fusió, rebase o --force-with-lease. No és un botó. |
Recuperar amb reflog (09-04) |
Gairebé cap interfície no l'exposa bé, i és la xarxa de seguretat principal. |
push --force-with-lease |
Moltes interfícies ofereixen --force a seques, que és la variant perillosa. |
Depurar (GIT_TRACE, check-ignore, lampisteria) (09-06) |
No hi ha equivalent gràfic. |
bisect (06-02) |
Automatitzable amb --run, impossible d'automatitzar amb clics. |
Consultes precises de log (06-04) |
-S, -G, --follow, -L :funció:fitxer: expressivitat que cap interfície no iguala. |
| Qualsevol cosa que no entenguis | Si no saps què passarà, escriu l'ordre i llegeix-ne la sortida. |
L'última fila és la important. L'error que cal evitar no és fer servir la interfície: és fer-la servir per a alguna cosa que no entens. Si saps exactament què fa un botó, prem el botó; t'estalvia teclejar. Si no ho saps, escriu l'ordre, encara que triguis més, perquè estàs pagant l'aprenentatge una sola vegada.
- Clients gràfics i visors d'historial
Els clients gràfics dedicats van un pas més enllà que la integració d'un editor: són aplicacions l'única feina de les quals és Git.
En què són realment superiors
El graf. Un historial amb branques paral·leles i fusions és un graf dirigit acíclic (lliçó 03-01), i un graf s'entén molt millor dibuixat que en text. Veure d'un cop d'ull on va divergir una branca, quines fusions hi va haver i quins commits són de qui és genuïnament més ràpid en una interfície.
Al terminal, l'equivalent decent:
I amb els formats de la lliçó 06-04, molt llegible:
Però amb més de tres o quatre branques vives, el dibuix ASCII es torna difícil de seguir. Aquí una interfície guanya.
La comparació de dos commits arbitraris. Seleccionar dos punts de l'historial i veure'n la diferència és més còmode amb el ratolí que recordant dos hashos.
L'exploració d'un repositori aliè. Quan arribes nou a un projecte, recórrer visualment el seu historial dona una intuïció de com treballa l'equip que costa més obtenir llegint text.
Git porta els seus
Sense instal·lar res, Git inclou dues eines gràfiques mínimes:
Són austeres, però són a tot arreu i no depenen que ningú les mantingui. gitk --all --date-order continua sent una manera ràpida de mirar un graf en un servidor on no instal·laràs res.
El risc específic dels clients gràfics
La seva facilitat fa que s'executin operacions costoses sense pensar-les. Arrossegar una branca sobre una altra pot llançar un rebase de vint commits. Un menú contextual pot oferir «Força l'enviament» al costat d'«Envia», sense distingir entre --force i --force-with-lease (lliçó 09-03).
Consell concret: si el teu client gràfic ofereix enviament forçat, comprova a la seva configuració quina de les dues variants fa servir. Si és --force a seques i no es pot canviar, fes aquesta operació al terminal. La diferència entre les dues és la feina d'un company.
- El terminal com a entorn de Git: prompt i autocompleció
Si decidiràs al terminal, convé que el terminal estigui ben equipat. Dos ajustos amb una relació esforç/benefici enorme.
Estat de Git al prompt
Veure la branca actual i l'estat de l'arbre a cada línia del terminal elimina una classe sencera d'errors: confirmar a la branca equivocada, oblidar que hi ha un rebase a mig fer, no adonar-te que hi ha canvis sense confirmar.
Git distribueix el guió oficial. Sol estar ja instal·lat amb Git:
# Localitzar-lo (la ruta varia segons el sistema)
ls /usr/share/git/completion/git-prompt.sh 2>/dev/null
ls /usr/share/git-core/contrib/completion/git-prompt.sh 2>/dev/null
ls /usr/lib/git-core/git-sh-prompt 2>/dev/nullI es configura a ~/.bashrc:
# Carregar el guió de prompt de Git
source /usr/lib/git-core/git-sh-prompt
# Quina informació mostrar
export GIT_PS1_SHOWDIRTYSTATE=1 # * si hi ha canvis, + si n'hi ha de preparats
export GIT_PS1_SHOWSTASHSTATE=1 # $ si hi ha res al desament temporal
export GIT_PS1_SHOWUNTRACKEDFILES=1 # % si hi ha fitxers sense seguiment
export GIT_PS1_SHOWUPSTREAM="auto" # < > = respecte al remot
export GIT_PS1_SHOWCOLORHINTS=1 # color segons l'estat
# El prompt
PS1='\u@\h:\w$(__git_ps1 " (%s)")\$ 'El resultat a la pràctica:
ana@portatil:~/gestor-tasques (main=)$ ana@portatil:~/gestor-tasques (GT-231-filtre-ocultes *%<)$ ana@portatil:~/gestor-tasques (GT-231-filtre-ocultes|REBASE 2/5)$
Llegeix-los d'esquerra a dreta:
main=: amain, sincronitzada amb el remot.GT-231-filtre-ocultes *%<: hi ha canvis sense preparar (*), fitxers sense seguiment (%) i el remot va per davant (<), així que toca unfetch.|REBASE 2/5: hi ha un rebase a mig fer, al pas 2 de 5. Aquesta és la que evita més disgustos: és exactament la situació en què algú s'aixeca a buscar cafè, torna i no entén per quègit statusdiu coses estranyes (lliçó 09-01).
A macOS amb zsh, el Bruno té l'equivalent integrat a la configuració del seu intèrpret d'ordres; i a Windows, la Carla el té de sèrie a Git Bash. L'important no és quin guió facis servir, sinó que la branca estigui sempre a la vista.
Autocompleció
Git distribueix també el seu guió de compleció, que completa subordres, opcions, noms de branca, d'etiqueta i de remot:
Amb ell, git switch GT-<TAB> ofereix les branques que comencen per GT-. En un repositori amb moltes branques és una millora enorme, i a més evita l'error de teclejar malament un nom de branca, que a Git a vegades no falla sinó que crea alguna cosa nova.
Un detall valuós: la compleció també funciona amb els teus àlies si estan definits com a àlies de Git (lliçó 06-04):
git config --global alias.hist "log --graph --oneline --decorate --all"
git config --global alias.st "status -sb"
git config --global alias.ultim "log -1 HEAD --stat"Davant dels àlies de l'intèrpret d'ordres (alias gs='git status'), els àlies de Git tenen tres avantatges: viatgen amb la teva configuració a qualsevol màquina, funcionen igual a Bash, zsh i Git Bash, i són visibles per a qui llegeixi la teva configuració. Els àlies de l'intèrpret són més curts d'escriure; fes servir tots dos, cadascun per al que li toca.
- Sistemes de tiquets: tancant la convenció
GT-NNN
GT-NNNPortem tot el curs escrivint GT-231 a branques i missatges. Toca explicar per a què serveix exactament i què s'hi aconsegueix.
Els tres punts de contacte
flowchart LR
T["Tiquet GT-231<br/>al gestor"] --> R["Branca<br/>GT-231-filtre-ocultes"]
R --> C["Commits<br/>feat: GT-231 ..."]
C --> P["Proposta<br/>'Tanca GT-231'"]
P --> M["Fusió a main"]
M --> T2["Tiquet tancat<br/>automàticament"]
M --> V["Etiqueta v1.4.0<br/>registre de canvis amb GT-231"]
La cadena completa de traçabilitat té tres baules que cal mantenir a mà i una que s'automatitza:
- La branca porta l'identificador.
GT-231-filtre-ocultes. Sense això, d'aquí a sis mesos ningú no sabrà què era aquella branca. - Els commits el porten. Amb Conventional Commits (lliçó 08-01), a l'assumpte o en un peu:
feat(tasques): GT-231 filtra les tasques ocultes del llistat Les tasques arxivades deixen d'aparèixer al llistat principal. S'afegeix la marca `oculta` i es filtra a pintaLlista(). Refs: GT-231
- La proposta ho declara, amb la paraula clau que la plataforma reconeix (
Tanca GT-231,Closes GT-231,Fixes GT-231, segons l'eina). - En integrar, el tiquet es tanca sol i queda enllaçat al commit d'integració.
La pregunta que això respon
La traçabilitat no és burocràcia. És la capacitat de respondre, en trenta segons i sense preguntar a ningú, a aquestes quatre preguntes:
| Pregunta | Com es respon |
|---|---|
«Què va canviar amb GT-231?» |
Buscar l'identificador a l'historial |
| «Per què aquesta línia és així?» | git blame → commit → tiquet → discussió completa |
«És GT-231 en producció?» |
És el seu commit a l'etiqueta desplegada? |
| «Què entra a la versió 1.4.0?» | Els tiquets dels commits entre v1.3.0 i v1.4.0 |
I les ordres corresponents, totes ja conegudes:
# Quins commits esmenten GT-231?
git log --grep='GT-231' --oneline
# A quines branques i etiquetes és aquest commit?
git branch -a --contains 4f8a2e6
git tag --contains 4f8a2e6
# Quins tiquets entren a la pròxima versió?
git log v1.3.0..main --format=%s | grep -oE 'GT-[0-9]+' | sort -u
# És GT-231 a l'etiqueta que hi ha en producció?
git merge-base --is-ancestor 4f8a2e6 v1.3.0 && echo "sí" || echo "no"Aquesta última ordre és la que es fa servir de debò quan algú escriu «això continua fallant en producció»: comprova objectivament si la correcció hi va arribar a ser.
Automatitzar la meitat tediosa
Escriure GT-231 a cada missatge s'oblida. Es pot automatitzar amb un hook (lliçó 06-01) que l'extregui del nom de la branca:
#!/bin/sh
# .git/hooks/prepare-commit-msg
# Afegeix l'identificador del tiquet, pres del nom de la branca.
FITXER_MSG="$1"
ORIGEN="$2"
# No tocar fusions, condensats ni missatges ja escrits amb -m editat
case "$ORIGEN" in
merge|squash) exit 0 ;;
esac
BRANCA=$(git symbolic-ref --short HEAD 2>/dev/null) || exit 0
TIQUET=$(printf '%s' "$BRANCA" | grep -oE '^GT-[0-9]+')
[ -z "$TIQUET" ] && exit 0
grep -q "$TIQUET" "$FITXER_MSG" && exit 0
# Inserir el tiquet al principi de la primera línia
sed -i.bak "1s/^/$TIQUET /" "$FITXER_MSG" && rm -f "$FITXER_MSG.bak"I la validació del costat del servidor, que és la que garanteix que es compleix, ja la vam veure a la lliçó 06-01 com a hook update i a la 07-06 com a comprovació de la canonada.
Recorda el repartiment de responsabilitats que vam establir: el hook client ajuda, el hook servidor obliga. Un prepare-commit-msg és una comoditat; si el requisit és real, ha d'estar comprovat també al servidor o a la CI, perquè els hooks locals no es distribueixen amb el repositori i cadascú se'ls pot saltar amb --no-verify.
- Eines de qualitat: linters, formatadors i
.editorconfig
.editorconfigUn linter assenyala problemes; un formatador imposa un estil. En un equip, tots dos s'han d'executar de manera automàtica, perquè l'estil discutit a les revisions és temps perdut.
La pregunta interessant és on enganxar-los, i hi ha tres llocs possibles.
Les tres posicions
| On | Quan actua | Avantatge | Inconvenient |
|---|---|---|---|
| Editor (en desar) | Instantani | Mai no veus l'error | Depèn de la configuració de cada persona |
Hook client (pre-commit) |
En confirmar | Impedeix crear el commit brut | No es distribueix; se salta amb --no-verify; alenteix |
| CI (07-06) | En enviar / a la proposta | Obligatori de debò, igual per a tothom | Cicle lent: te n'assabentes minuts després |
La combinació correcta és editor + CI, amb el hook com a opció de qui el vulgui. L'editor et dona la resposta immediata, la CI garanteix el compliment. El hook pre-commit és còmode però no pot ser l'única defensa, pel motiu de sempre: no viatja amb el repositori.
Un pre-commit ben fet té un detall que gairebé tothom oblida: ha de comprovar el que és a l'índex, no el que és al disc. Si tens canvis sense preparar, comprovar el fitxer del disc valida una cosa que no és la que confirmaràs:
#!/bin/sh
# .git/hooks/pre-commit
# Comprova el format NOMÉS del que entrarà al commit.
# Desar els canvis no preparats per no validar-los
git stash push --keep-index --include-untracked --quiet --message "pre-commit"
RESTAURAR=$?
FITXERS=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|css)$')
CODI=0
if [ -n "$FITXERS" ]; then
echo "$FITXERS" | xargs npx eslint || CODI=1
fi
# Restaurar sempre, falli o no la comprovació
[ $RESTAURAR -eq 0 ] && git stash pop --quiet
exit $CODITres coses que mereixen atenció:
--diff-filter=ACMexclou els fitxers esborrats: no té sentit passar el linter a una cosa que ja no existeix. És l'error més freqüent en aquests hooks.- El
stash push --keep-indexaparta el que no està preparat (lliçó 05-04) perquè el linter vegi exactament el contingut que es confirmarà. - La restauració es fa tant si passa com si falla la comprovació. Un hook que et deixa la feina al desament temporal quan falla és un hook que la gent desactiva.
.editorconfig
Un fitxer petit i molt rendible, que viatja al repositori i que gairebé tots els editors respecten (alguns de sèrie, d'altres amb una extensió):
# .editorconfig a l'arrel de gestor-tasques
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
[*.{bat,cmd}]
end_of_line = crlf
[Makefile]
indent_style = tabEl seu valor és resoldre a l'origen el que .gitattributes (lliçó 08-04) resol a la frontera del repositori. Són complementaris, i convé tenir clar el repartiment:
.editorconfig |
.gitattributes |
|
|---|---|---|
| Qui l'aplica | L'editor, en escriure el fitxer | Git, en confirmar i en extreure |
| Quan | Mentre edites | A add/commit/checkout |
| Si no està suportat | No passa res, s'ignora | Git sempre l'aplica |
| Abast | Estil d'edició | Normalització, diff, fusió, filtres, exportació |
Amb tots dos, el problema dels finals de línia entre Ubuntu, macOS i Windows 11 —el GT-190 que vam resoldre a la lliçó 08-04— s'ataca per partida doble: l'editor de la Carla escriu LF des del principi, i Git normalitza igualment per si de cas.
- Revisió i anàlisi: comprovacions d'estat
Les plataformes d'allotjament tenen un mecanisme que unifica tot el que és automàtic: els estats de commit (o comprovacions). Qualsevol sistema extern pot publicar, contra un hash de commit concret, un veredicte: pendent, correcte, fallit.
flowchart TD
C["Commit a1b2c3d<br/>enviat a la proposta"] --> CI["Proves"]
C --> LINT["Linter"]
C --> COB["Cobertura"]
C --> SEC["Anàlisi de seguretat"]
C --> EST["Anàlisi estàtica"]
CI --> E["Estats del commit a1b2c3d"]
LINT --> E
COB --> E
SEC --> E
EST --> E
E --> RP["Branca protegida:<br/>tots en verd?"]
RP -->|sí| OK["Es pot integrar"]
RP -->|no| NO["Integració bloquejada"]
L'important conceptualment: l'estat s'associa a un hash de commit, no a una branca ni a una proposta. És coherent amb tot el model de Git (lliçó 01-04): el commit és immutable, així que un veredicte sobre ell continua sent vàlid per sempre. Si reescrius la branca, els commits nous tenen hashos diferents i les comprovacions s'executen una altra vegada, perquè són objectes diferents.
D'aquí una conseqüència pràctica que confon molta gent: després d'un rebase i un push --force-with-lease, totes les comprovacions es tornen a executar. No és una fallada de la plataforma. És que el commit ja no és el mateix.
Quins tipus de comprovació mereixen ser bloquejants
| Tipus | Bloquejant? | Motiu |
|---|---|---|
| Proves | Sí | Una fallada és una fallada objectiva |
| Compilació / empaquetatge | Sí | Si no compila, no hi ha res a revisar |
| Linter | Sí | És determinista i es corregeix en segons |
| Secrets detectats (08-05) | Sí | El cost d'un fals negatiu és enorme |
| Vulnerabilitats conegudes en dependències | Segons la gravetat | Bloquejar per tot genera fatiga i s'acaba ignorant |
| Cobertura de proves | Amb matisos | Bloquejar per llindar absolut castiga qui toca codi antic; millor per variació |
| Anàlisi estàtica heurística | No | Produeix falsos positius; que informi, no que bloquegi |
La regla: bloqueja amb el que és determinista, informa amb el que és heurístic. Una comprovació que falla sovint sense motiu real ensenya l'equip a ignorar els vermells, i el dia que el vermell és de debò, ningú no el mira.
El detall que cal saber sobre la cobertura
Mesurar la cobertura sobre el projecte sencer produeix una mètrica que gairebé no es mou i que castiga arbitràriament. L'útil és mesurar la cobertura de les línies que la proposta afegeix o modifica, i això es calcula, com no, a partir d'un diff:
# Línies que toca aquesta branca respecte del punt de divergència
git diff --unified=0 origin/main...HEAD -- '*.js'Aquest --unified=0 dona el diff sense context: només les línies realment canviades, amb els seus números. És el que consumeixen les eines de cobertura diferencial. I una altra vegada els tres punts (lliçó 07-02), pel mateix motiu de sempre: volem el que la branca aporta, no la diferència amb un main que ha avançat.
format-patch, am i request-pull com a pont entre mons
format-patch, am i request-pull com a pont entre monsA la lliçó 10-01 vam veure aquestes ordres com el flux natiu del kernel. Aquí interessen per un altre motiu: són el format d'intercanvi universal entre qualsevol eina i qualsevol repositori.
Un pedaç generat per format-patch és text pla que es pot enganxar en un tiquet, adjuntar a un correu, desar en un arxiu o publicar en una pàgina web. No necessita servidor, ni compte, ni protocol. I git am l'aplica conservant l'autoria i el missatge, cosa que copiar i enganxar el codi no fa mai.
Situacions reals on això salva el dia
1. Enviar un canvi a algú sense accés compartit. Un consultor extern, un company d'una altra empresa, algú en una xarxa aïllada.
# Origen
git format-patch main --stdout > /tmp/GT-244.patch
# Destinació: veure què faria abans d'aplicar-lo
git apply --stat /tmp/GT-244.patch
git apply --check /tmp/GT-244.patch
# Aplicar-lo conservant l'autoria i el missatge
git am /tmp/GT-244.patchgit apply --check és l'assaig previ: diu si el pedaç s'aplicaria netament sense tocar res. I --stat mostra quins fitxers afectaria. Convé executar tots dos abans d'aplicar res que vingui de fora.
2. Moure un commit entre dos repositoris que no es coneixen. Quan cherry-pick no serveix perquè no comparteixen història:
El -3 habilita la fusió a tres bandes si el context no coincideix exactament. És el que converteix un pedaç fràgil en un de raonablement robust.
3. Arxivar un canvi com a text llegible. Un pedaç és autodescriptiu i sobreviu a qualsevol migració de plataforma. Per a canvis que cal conservar per motius d'auditoria, és un format millor que un enllaç a un servidor que potser no existirà d'aquí a deu anys.
4. Revisar sense plataforma. format-patch produeix una cosa que es llegeix de dalt a baix en qualsevol editor, amb el missatge del commit a sobre del diff. Per revisar una sèrie de commits en un avió, és millor que cap interfície web.
git request-pull en un flux modern
Ja el vam veure a la lliçó anterior. Aquí només un ús concret que és sorprenentment útil: generar el text d'una proposta.
Produeix un resum amb el commit base, la llista de commits agrupats per autor i el diffstat. Enganxat a la descripció d'una proposta gran, estalvia a qui revisa la feina d'esbrinar-ne l'abast.
I com a cola entre els dos mons: una proposta de plataforma es pot convertir en pedaços, perquè tota proposta és, per sota, un conjunt de commits en una branca.
git fetch origin refs/pull/42/head:proposta-42
git format-patch main..proposta-42 -o /tmp/proposta-42/Aquest refs/pull/42/head és un refspec (lliçó 04-01) que les plataformes exposen per accedir a les branques de les propostes. Serveix també per revisar-les en local:
git fetch origin refs/pull/42/head:proposta-42
git switch proposta-42
npm test
git diff main...proposta-42Revisar una proposta executant-la en lloc de només llegint-la és, de bon tros, la manera més eficaç de revisar. I és una de les coses que la comoditat de la interfície web ha fet que molta gent deixi de fer.
- Com triar què automatitzar
Tanquem amb el criteri, que és el que dona unitat a tot l'anterior.
Automatitza quan
- La tasca és repetitiva i determinista: formatar, ordenar imports, comprovar el format d'un missatge.
- L'error és freqüent i detectable: oblidar el tiquet, confirmar un fitxer de configuració amb credencials, deixar espais al final.
- La comprovació és objectiva: passa o no passa, sense criteri humà.
- L'estalvi és per a tot l'equip, no només per a tu.
No automatitzis quan
- L'operació és irreversible i contextual: reescriptures, enviaments forçats, esborrats.
- La decisió requereix criteri: si un canvi és una bona idea, si l'abstracció és la correcta, si el missatge explica bé el perquè.
- L'automatització amaga alguna cosa que necessites entendre.
- El cost d'un fals positiu és alt: si bloqueja la feina de l'equip sense motiu, es desactivarà, i amb ella es desactivaran les comprovacions bones.
El muntatge recomanat per a un equip com el de gestor-tasques
Recapitulant tota la lliçó en una configuració concreta:
| Capa | Què hi ha | Cost |
|---|---|---|
| Editor | Diferències al marge, blame en línia, formatatge en desar, .editorconfig |
Configuració inicial |
| Terminal | Prompt amb branca i estat, autocompleció, àlies de Git (06-04) | Mitja hora, una vegada |
| Hooks client (06-01) | prepare-commit-msg per al tiquet; pre-commit lleuger opcional |
Baix, i opcional |
| Repositori | .gitignore, .gitattributes, .editorconfig, .git-blame-ignore-revs, CONTRIBUTING.md |
Un dia, una vegada |
| CI (07-06) | Proves, linter, secrets, format de missatges — bloquejants | Manteniment continu |
| Plataforma | Branca protegida, plantilla de proposta, tancament automàtic de tiquets | Configuració inicial |
Fixa't que la major part del benefici és a la fila del repositori: quatre fitxers de text que viatgen amb el projecte i que beneficien tothom sense que ningú hagi de configurar la seva màquina.
Errors Habituals i Consells
Error 1: fer servir «Sincronitza» sense saber què fa. És l'error d'aquesta lliçó. Comprova git config --get pull.rebase i decideix conscientment. Si el botó fa pull --rebase i tu has publicat la branca, cada sincronització pot reescriure commits que altres ja tenen (lliçó 05-01).
Error 2: instal·lar hooks que ningú més no té. Els hooks no es distribueixen amb el repositori (lliçó 06-01). Si el teu equip depèn d'una comprovació, ha d'estar a la CI o en un hook de servidor. Els hooks locals són comoditat personal, mai garantia.
Error 3: hooks lents. Un pre-commit que triga quinze segons fa que la gent confirmi menys vegades i amb canvis més grans, o que faci servir --no-verify sistemàticament. Un hook client ha de trigar menys de dos segons i comprovar només els fitxers preparats.
Error 4: linter sobre el disc en lloc de sobre l'índex. Si tens canvis sense preparar, valides una cosa que no és la que confirmaràs. Fes servir git diff --cached --name-only --diff-filter=ACM i el truc del stash --keep-index.
Error 5: refiar-te del blame de l'editor sense .git-blame-ignore-revs. Després d'un reformatatge massiu, el blame et dirà que tot el fitxer el va escriure qui va passar el formatador. Deu minuts de configuració ho arreglen per sempre i per a tot l'equip.
Error 6: bloquejar la integració amb comprovacions sorolloses. Una anàlisi heurística amb falsos positius, posada com a bloquejant, fa que l'equip aprengui a ignorar els vermells. Bloqueja amb el que és determinista, informa amb la resta.
Error 7: revisar només per la interfície web. Per a propostes grans, porta't la branca i executa-la. git fetch origin refs/pull/N/head:proposta-N i git diff main...proposta-N donen una revisió molt millor que un navegador.
Consell 1: mira el registre d'ordres de la teva eina durant una setmana. Gairebé totes tenen una consola on mostren el que executen. És la manera més ràpida d'aprendre la correspondència entre botons i ordres.
Consell 2: posa l'estat de Git al prompt avui mateix. De tot el que hi ha en aquesta lliçó, és el que evita més errors per minut invertit, sobretot l'indicador d'operació en curs (|REBASE, |MERGING).
Consell 3: fica la configuració compartida al repositori. .editorconfig, .gitattributes, .gitignore i .git-blame-ignore-revs són quatre fitxers de text que fan que el projecte es comporti igual per a tothom sense dependre de la màquina de cadascú.
Consell 4: quan passi alguna cosa estranya a la interfície, ves al terminal. git status, git log --oneline --graph -20 i git reflog et diuen on ets realment. La interfície mostra una interpretació; les ordres mostren l'estat.
Exercicis
Exercici 1: traduir botons a ordres
La Carla fa servir el seu editor per a tot. Descriu què està passant en cada situació i quina ordre hi ha a sota:
A. Prem «Sincronitza els canvis» amb tres commits locals sense enviar. En acabar, els seus tres commits tenen hashos diferents dels d'abans.
B. Prem «Descarta els canvis» en un fitxer amb dues hores de feina sense confirmar. Pregunta si el pot recuperar amb git reflog.
C. Prem «Desfés l'últim commit» i els seus canvis reapareixen com a preparats al plafó de canvis.
Exercici 2: un hook de missatge que no molesta
Escriu un hook commit-msg per a gestor-tasques que:
- Rebutgi el commit si l'assumpte no segueix Conventional Commits (
tipus(àmbit opcional): descripció). - Rebutgi el commit si l'assumpte supera els 72 caràcters.
- Avisi però no rebutgi si el missatge no esmenta cap
GT-NNN. - No molesti en fusions ni en commits de
rebase/revertautomàtics.
Explica per què el punt 3 avisa en lloc de rebutjar.
Exercici 3: revisar una proposta gran sense la interfície web
El Diego ha obert la proposta número 57 a gestor-tasques, amb 14 commits i 800 línies canviades. L'Ana la vol revisar de debò: entendre els canvis, executar les proves i deixar comentaris fonamentats.
Escriu la seqüència d'ordres que faries servir, explicant què aporta cada pas. Inclou què faries si el Diego envia una versió corregida i vols veure només què ha canviat respecte del que ja vas revisar.
Solucions
Solució 1
A. «Sincronitza» ha fet pull --rebase i després push.
Els hashos canvien perquè el rebase (lliçó 05-01) reconstrueix cada commit sobre la nova base: canvia el pare, i com que el hash d'un commit inclou el del seu pare (lliçó 01-04), canvia el hash sencer.
El que hi ha a sota, segons la seva configuració:
És un problema? Depèn de si la branca estava publicada:
- Branca local, sense enviar mai: no passa res, és el que es vol.
- Branca publicada i amb algú més treballant-hi: acaba de reescriure història compartida. El
pushposterior o bé va ser rebutjat, o bé el va forçar l'eina, deixant els altres amb una divergència (lliçó 09-03).
Recomanació: que la Carla comprovi conscientment aquest ajust. pull.rebase = true és una bona opció per defecte per a branques personals, però amb un botó que ho dispara sense preguntar convé saber-ho.
B. «Descarta els canvis» és git restore <fitxer>, i NO, no es recupera amb el reflog.
Aquesta és la distinció crítica de tot el mòdul 9:
| Recuperable? | Per què | |
|---|---|---|
| Un commit «perdut» | Sí, amb git reflog (09-04) |
És un objecte a la base de dades |
| Contingut que va estar preparat | Gairebé sempre, amb git fsck --lost-found (09-04) |
git add va crear un objecte blob |
| Canvis mai preparats ni confirmats | No | No van arribar a ser mai un objecte |
Les seves dues hores de feina, si no va fer mai git add, no existeixen per a Git. Només queda mirar l'historial local de canvis del mateix editor, que molts desen i que és l'única xarxa de seguretat en aquest cas.
La lliçó: git add no és només «preparar per confirmar», és també «desar una còpia recuperable». És l'argument definitiu per preparar aviat i sovint.
C. «Desfés l'últim commit» ha estat git reset --soft HEAD~1.
El commit desapareix de la branca i els seus canvis queden a l'índex (per això apareixen com a preparats). Amb --mixed (el valor per defecte de reset) apareixerien com a modificats però no preparats; amb --hard haurien desaparegut.
Que l'editor faci servir --soft és el correcte per a «desfés el commit però conserva la feina». I el commit original continua existint: git reflog el mostra i git reset --hard HEAD@{1} el restaura (lliçó 09-02).
Solució 2
#!/bin/sh
# .git/hooks/commit-msg
# Valida el missatge de confirmació de gestor-tasques.
FITXER="$1"
# Primera línia no buida i que no sigui comentari
ASSUMPTE=$(grep -v '^#' "$FITXER" | sed '/^[[:space:]]*$/d' | head -1)
# --- Exclusions: no molestar en allò automàtic ---
case "$ASSUMPTE" in
"Merge "*|"Revert "*|"fixup!"*|"squash!"*|"amend!"*)
exit 0 ;;
esac
# Tampoc durant un rebase o una fusió en curs
GITDIR=$(git rev-parse --git-dir)
if [ -d "$GITDIR/rebase-merge" ] || [ -d "$GITDIR/rebase-apply" ] \
|| [ -f "$GITDIR/MERGE_HEAD" ]; then
exit 0
fi
ERROR=0
# --- Regla 1: Conventional Commits ---
PATRO='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\([a-z0-9-]+\))?!?: .+'
if ! printf '%s' "$ASSUMPTE" | grep -qE "$PATRO"; then
echo "ERROR: l'assumpte no segueix Conventional Commits."
echo " Rebut: $ASSUMPTE"
echo " Format: tipus(àmbit): descripció"
echo " Tipus: feat fix docs style refactor perf test build ci chore"
ERROR=1
fi
# --- Regla 2: longitud de l'assumpte ---
LONGITUD=$(printf '%s' "$ASSUMPTE" | wc -c)
if [ "$LONGITUD" -gt 72 ]; then
echo "ERROR: l'assumpte té $LONGITUD caràcters (màxim 72)."
ERROR=1
fi
# --- Regla 3: tiquet, només avís ---
if ! grep -qE 'GT-[0-9]+' "$FITXER"; then
echo "AVÍS: el missatge no esmenta cap tiquet GT-NNN."
echo " Si el canvi en correspon a un, afegeix-l'hi amb 'git commit --amend'."
fi
exit $ERRORPer què el punt 3 només avisa:
-
No sempre hi ha tiquet legítimament. Corregir una errada del
README.md, ajustar la configuració de la CI o unchorede manteniment no sempre tenen tiquet, i obligar a inventar-ne un degrada el sistema de tiquets: s'omple d'entrades falses creades per satisfer el hook. -
Un hook que rebutja massa es desactiva. Tan bon punt algú ha de fer servir
--no-verifyuna vegada per setmana, deixa de fer servir el hook. I en desactivar-lo perd també les regles 1 i 2, que sí que són valuoses. Una regla estricta de més debilita les bones. -
Les regles 1 i 2 són objectives; la 3 és contextual. El format de l'assumpte no admet excepció raonable. La presència de tiquet sí. És la mateixa distinció de l'apartat 8: bloqueja amb el que és determinista, informa amb el que és heurístic.
-
Si l'equip decideix que el tiquet és obligatori, aquesta regla ha d'estar al servidor o a la CI, no en un hook local. Un hook local no és una garantia per a ningú més que per a tu.
Les exclusions del principi també importen: un hook que rebutja els missatges generats per git merge o per git revert converteix operacions normals en un calvari, i és la causa número u que els hooks acabin a la paperera.
Solució 3
# 1. Portar la branca de la proposta sense dependre de la interfície web
git fetch origin refs/pull/57/head:proposta-57
# 2. Abast general: què toca i quant?
git diff --stat main...proposta-57Els tres punts són obligatoris (lliçó 07-02): donen el que la branca aporta des que es va separar de main, no la diferència amb el main actual. Amb dos punts, qualsevol avanç de main apareixeria com si el Diego l'hagués desfet.
Aquí ja s'aprèn molt. Catorze commits ben partits i ben anomenats es revisen d'un en un; catorze commits anomenats «apanys» i «wip» s'han de revisar com un bloc, i mereix un comentari demanant que els netegi amb rebase -i (lliçó 05-02).
# 4. Revisar commit a commit, amb el missatge davant del diff
git log --reverse -p main..proposta-57
# 5. Executar de debò: això és el que la interfície web no pot fer
git switch proposta-57
npm ci && npm test
npm start # i provar el comportament a mà
# 6. Comprovacions específiques
git diff main...proposta-57 --stat -- '*.test.js' # hi ha proves?
git log main..proposta-57 --format=%B | grep -c 'GT-' # referencien el tiquet?
git diff main...proposta-57 | grep -nE '(clau|token|password|secret)' # secretsEl pas 5 és el que distingeix una revisió real d'una lectura. Executar la branca detecta coses que cap diff no ensenya: que la interfície queda descol·locada, que hi ha un missatge d'error incomprensible, que una operació triga tres segons.
Per revisar la segona versió, després que el Diego refaci la branca:
# Desar la referència del que ja vaig revisar, ABANS de portar el que és nou
git branch proposta-57-v1 proposta-57
# Portar la versió corregida (forçant, perquè el Diego ha reescrit la seva branca)
git fetch origin +refs/pull/57/head:proposta-57
# La pregunta clau: què ha canviat respecte del que ja vaig revisar?
git range-diff main proposta-57-v1 proposta-57git range-diff (lliçó 07-02) és exactament l'eina per a això: compara dues versions d'una mateixa sèrie de commits i mostra un diff de diffs. Aparella els commits equivalents i marca cadascun:
=sense canvis respecte de la versió anterior.!mateix commit però amb contingut modificat, i mostra què hi ha canviat a dins.</>commits eliminats o afegits a la nova versió.
En una proposta de 14 commits on el Diego només n'ha corregit dos, range-diff t'ensenya aquests dos i t'estalvia revisar els altres dotze una altra vegada. És l'ordre que fa sostenible revisar sèries llargues, i el motiu pel qual el model del kernel (lliçó 10-01) es pot permetre arribar a la versió 5 d'una sèrie.
El + de +refs/pull/57/head:proposta-57 és el refspec forçat (lliçó 04-01): permet actualitzar la referència local encara que l'avanç no sigui de fast-forward, que és justament el que passa quan l'altre costat ha reescrit la seva branca.
Conclusió
Git és un motor; tota la resta és carrosseria. Aquesta lliçó ha recorregut aquesta carrosseria amb un criteri constant: fer servir el que aporta, sabent sempre què hi ha a sota.
- Els editors i IDE aporten de debò en allò visual: diferències al marge, resolució de conflictes amb la base comuna a la vista (
merge.conflictStyle = zdiff3),blameen línia i preparació per fragments amb el ratolí. Cada botó té una ordre al darrere, i el més perillós és «Sincronitza», que pot reescriure el teu historial segons un ajust que potser no recordes haver posat. - Al terminal convé continuar fent tot el que és irreversible o conceptual: reescriptures, divergències,
reflog,--force-with-lease,bisect, depuració i consultes precises delog. La regla: fes servir la interfície per mirar, el terminal per decidir. - Els clients gràfics guanyen clarament dibuixant el graf i comparant punts arbitraris de l'historial. Git porta els seus (
gitk,git gui) i són a tot arreu. - El terminal ben equipat —estat de Git al prompt, autocompleció i àlies de Git (06-04)— és la millora amb millor relació esforç/benefici del mòdul. L'indicador
|REBASE 2/5evita per si sol una categoria sencera d'embolics. - Els sistemes de tiquets tanquen la convenció
GT-NNNque hem fet servir tot el curs: branca, commits i proposta porten l'identificador, la integració tanca el tiquet, i el resultat és poder respondre en trenta segons a «què va canviar amb GT-231?» i «és en producció?». - Les eines de qualitat s'enganxen en tres llocs —editor, hook client i CI— i la combinació sana és editor + CI: el primer dona resposta immediata, la segona garanteix el compliment, perquè els hooks locals ni es distribueixen ni obliguen.
.editorconfigresol a l'origen el que.gitattributesresol a la frontera. - Les comprovacions d'estat s'associen a un hash de commit, no a una branca: per això reescriure la branca les torna a llançar totes. Bloqueja amb el que és determinista, informa amb el que és heurístic.
format-patch,amirequest-pullsón el format d'intercanvi universal: mouen un canvi amb la seva autoria i el seu missatge entre repositoris que no es coneixen, sense servidor ni permisos. Irefs/pull/N/headpermet portar qualsevol proposta a local per revisar-la executant-la, que és l'única revisió que troba certs problemes.
La idea de fons, que és la mateixa amb què hem obert:
Automatitza allò repetitiu i determinista. Entén sempre quina ordre hi ha a sota. I reserva el terminal per a allò irreversible.
El que ve
Hi ha un tipus de fitxer que trenca tot el que hem muntat fins aquí. L'editor no en pot mostrar les diferències, la interfície no en pot resoldre els conflictes, el linter no en té res a dir i git diff respon amb una línia seca: Binary files differ.
I el pitjor no és això. El pitjor és que Git en desa cada versió sencera, per sempre, i tothom qui cloni el repositori se les baixa totes. Un dissenyador que actualitza cinc vegades un fitxer de 80 MB acaba d'afegir 400 MB a l'historial de tothom, i esborrar-lo no serveix de res, perquè els objectes continuen sent-hi (lliçó 08-06).
A gestor-tasques aquest problema encara no existeix. Però l'equip incorporarà recursos gràfics, vídeos de demostració i els fitxers de disseny de components-ui, i convé resoldre-ho abans que l'historial estigui contaminat, no després.
La lliçó 10-03: Git LFS per a Fitxers Grans tanca el que vam deixar pendent a les lliçons 06-05, 08-04 i 08-06: què és exactament aquest filter=lfs diff=lfs merge=lfs -text que apareixia a .gitattributes, com se substitueix un fitxer per un punter de text, i què cal saber —incloses les limitacions incòmodes— abans d'adoptar-lo.
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ó
