Changes for src/fonaments.md: 2 added lines, 1 removed line.
Original line number
Diff line number
Diff line
@@ -10,8 +10,9 @@
-[Arquitectura dels frameworks](./fonaments/frameworks.md): quina arquitectura imposa un framework (peces comunes, model d'execució, eix d'opinió, capes, ORM).
-[Frameworks un per un](./fonaments/frameworks_taules.md): taules de consulta amb el vocabulari i les decisions per defecte de dotze frameworks.
-[Frameworks a la pràctica](./fonaments/frameworks_practica.md): llegir un projecte, triar framework, deixar peces substituïbles i posar ordre quan el framework no en posa.
-[Workflow Git](./fonaments/workflow_git.md): flux de treball amb Git, resolució de conflictes, operacions habituals i FAQ.
-[Workflow Git](./fonaments/workflow_git.md): flux de treball amb Git, resolució de conflictes i operacions habituals.
-[Git en equip](./fonaments/git_equip.md): estratègies de branques, pull requests, fluxos de la indústria (GitHub flow, trunk-based, Git flow), CI/CD i bones pràctiques de commit.
-[Preguntes freqüents de Git](./fonaments/git_faq.md): respostes breus als dubtes habituals (pull, upstream, desfer commits, reflog, .gitignore).
-[Docker bàsic](./fonaments/basic_docker.md): contenidors, Dockerfile, volums, Docker Compose i distribució d'imatges.
-[DevOps](./fonaments/devops.md): principis de la cultura DevOps i com aplicar-los al desenvolupament i l'operació.
-[Infrastructure as Code](./fonaments/iac.md): aprovisionament amb Terraform, configuració amb Ansible, gestió de secrets i integració amb CI/CD.
També fan la revisió més fàcil: el revisor pot seguir la PR commit a commit, com una història en capítols, en lloc d'enfrontar-se a un sol diff enorme.
Regla pràctica: fes commit de cada unitat lògica de treball per separat, ajudant-te de l'[staging area](./workflow_git.md#en-local) per triar què hi entra. Si el codi no està llest, utilitza [`git stash`](./workflow_git.md#descartar-tots-els-canvis-locals) per guardar-lo temporalment sense fer commit.
Regla pràctica: fes commit de cada unitat lògica de treball per separat, ajudant-te de l'[staging area](./workflow_git.md#en-local) per triar què hi entra. Si el codi no està llest, utilitza [`git stash`](./git_faq.md#descartar-tots-els-canvis-locals) per guardar-lo temporalment sense fer commit.
`git pull` és equivalent a fer `git fetch` seguit de `git merge`. La diferència pràctica és que amb fetch + merge pots inspeccionar els canvis remots abans d'integrar-los (amb `git log` o `git diff`), mentre que pull ho fa tot de cop.
```shell
# Amb fetch + merge (més control)
git fetch
git log --oneline main..origin/main # veure què ha canviat
git merge
# Amb pull (més ràpid)
git pull origin main
```
## `git pull`: merge o rebase?
Quan la teva branca local i la remota han divergit, `git pull` ha de combinar les dues històries, i pot fer-ho de dues maneres:
***Merge** (comportament per defecte): crea un commit de merge que uneix les dues línies. Conserva l'historial exacte, però hi deixa "bombolles" de merge com les que hem vist a l'[escenari amb conflicte](./workflow_git.md#escenari-amb-conflicte).
***Rebase**: reaplica els teus commits locals a sobre dels remots, deixant un historial lineal i més net. És la mateixa idea que [rebase per mantenir la branca al dia](./git_equip.md#rebase-per-mantenir-la-branca-al-dia), aplicada al `pull`.
Pensa en l'usuari 2 de l'[escenari amb conflicte](./workflow_git.md#escenari-amb-conflicte). Amb merge, obté el diamant que hem vist en aquell escenari. Amb rebase, el seu commit es reaplica a sobre de `segona 1`:
```mermaid
gitGraph
commit id: "primer commit"
commit id: "afegim pregunta"
commit id: "segona 1"
commit id: "segona 2'"
```
L'apòstrof de `segona 2'` indica que és un commit nou: el mateix canvi, però amb un altre hash. El conflicte s'hauria de resoldre igualment, durant el rebase.
Des de git 2.27, si no has triat estratègia, `git pull` mostra un avís demanant-te que en configuris una. Les opcions habituals:
```shell
git config --global pull.rebase true# pull sempre amb rebase (historial lineal)
git config --global pull.ff only # només permet pull si és fast-forward; si no, atura's
```
Amb `pull.ff only` (una opció prudent), si hi ha divergència git no fa res automàticament i decideixes tu si fer `git merge` o `git rebase`. Puntualment també pots forçar l'estratègia amb `git pull --rebase` o `git pull --no-rebase`.
Compte: no facis rebase de commits que ja hagis pujat i compartit, perquè en reescriu l'historial (com `--amend` o el push forçat).
## Vincular una branca local amb la remota (upstream)
Quan fas `git push` o `git pull` sense especificar el remot ni la branca, git necessita saber a quina branca remota correspon la teva branca local. Aquesta associació s'anomena _upstream_ o _tracking branch_.
Hi ha diverses maneres d'establir-la:
```shell
# Opció 1: al fer push per primera vegada, amb -u (o --set-upstream)
git push -u origin main
# Opció 2: explícitament, sense fer push
git branch --set-upstream-to=origin/main main
```
Un cop establerta l'associació, pots fer servir les comandes curtes:
```shell
git push # equivalent a git push origin main
git pull # equivalent a git pull origin main
```
Quan clones un repositori, git configura automàticament el tracking de la branca principal. Per això `git pull` funciona directament en un repositori clonat sense haver de fer `-u` primer.
Per veure quines branques locals tenen upstream configurat:
```shell
git branch -vv
```
La sortida mostra, entre claudàtors, la branca remota associada:
```text
feature d4e5f6a [origin/feature] un altre missatge
* main a1b2c3d [origin/main] últim missatge de commit
```
## El push m'ha estat rebutjat ("fetch first")
Si en fer `git push` reps un error com aquest:
```text
! [rejected] main -> main (fetch first)
error: failed to push some refs to '...'
```
vol dir que **algú ha pujat canvis al remot abans que tu**, i git no et deixa sobreescriure'ls. No és cap error greu: només cal que integris primer els canvis remots i tornis a pujar.
```shell
git pull # baixa i integra els canvis remots (fetch + merge)
# si hi ha conflictes, resol-los, fes git add i git commit
git push # ara sí
```
És exactament la situació de l'[escenari amb conflicte](./workflow_git.md#escenari-amb-conflicte). Recorda la regla d'or: sincronitza (pull) sovint per reduir les vegades que et trobes en aquesta situació.
## Veure els canvis abans del commit
```shell
git diff # canvis al working directory (no afegits al staging)
git diff --staged# canvis ja afegits al staging area
git diff HEAD # tots els canvis respecte l'últim commit
```
## Treure un arxiu afegit per error
Si encara no has fet push, pots treure l'arxiu de l'últim commit sense perdre els canvis locals:
```shell
git reset HEAD~1 --soft# desfà el commit, manté els canvis al staging
git restore --staged arxiu-erroni.txt # treu l'arxiu del staging
git commit -m"el commit correcte"
```
Si ja has fet push però vols treure l'arxiu del repositori sense esborrar-lo del disc:
```shell
git rm--cached arxiu-erroni.txt
# afegir-lo al .gitignore si cal
git commit -m"remove arxiu-erroni del repositori"
git push
```
## El .gitignore no ignora un arxiu
El `.gitignore` només afecta els arxius que git **encara no segueix** (untracked). Si un arxiu ja s'havia afegit al repositori abans d'incloure'l al `.gitignore`, git continuarà seguint-lo i els seus canvis. Per deixar de seguir-lo (sense esborrar-lo del disc), treu-lo de l'índex amb `--cached`:
```shell
git rm--cached arxiu.txt
git commit -m"deixa de seguir arxiu.txt"
```
A partir d'aquí, amb l'arxiu ja al `.gitignore`, git l'ignorarà. Per a una carpeta sencera, fes servir `git rm -r --cached carpeta`.
## Descartar tots els canvis locals
```shell
git reset --hard HEAD
```
Compte: això esborra tots els canvis no comesos. Si vols guardar-los temporalment per recuperar-los més tard:
```shell
git stash # guarda els canvis temporalment
# ... fas altres coses ...
git stash pop # recupera els canvis guardats
```
## Desfer o corregir l'últim commit
Mentre no hagis fet push, l'últim commit es pot desfer o modificar sense afectar ningú.
**Desfer el commit completament**, mantenint els canvis al working directory:
```shell
git reset --soft HEAD~1 # els canvis queden al staging, llestos per tornar a fer commit
git reset HEAD~1 # els canvis queden al working directory, fora del staging
```
**Desfer el commit i descartar els canvis** (irreversible):
```shell
git reset --hard HEAD~1
```
**Corregir l'últim commit** (afegir arxius oblidats o canviar el missatge):
```shell
# Canviar només el missatge
git commit --amend-m"nou missatge corregit"
# Afegir arxius que faltaven al commit
git add arxiu-oblidat.txt
git commit --amend--no-edit# manté el missatge original
```
`--amend` reescriu l'últim commit. Si ja has fet push, no és recomanable fer-ho perquè reescriu l'historial i pot causar problemes als companys.
## Tornar a l'estat del remot
Si vols descartar tots els canvis locals (commits, staging i working directory) i sincronitzar-te exactament amb el repositori remot:
```shell
git fetch origin
git reset --hard origin/main
```
Això mou el HEAD local al mateix commit que `origin/main`, descartant qualsevol commit local que no s'hagi pujat i qualsevol canvi pendent. Si tens arxius nous que no estan al repositori (untracked), no s'esborren. Per eliminar-los també:
```shell
git clean -fd# esborra arxius i carpetes untracked
```
Compte: ambdues operacions són irreversibles. Si no estàs segur de voler perdre els canvis, fes primer una còpia o un `git stash`.
## Recuperar commits perduts (reflog)
Si has perdut feina amb un `reset` o un rebase, sovint la pots recuperar. git guarda un registre de tots els llocs on ha estat el HEAD (cada commit, reset, merge, switch...) durant un temps. Es consulta amb `git reflog`:
```shell
git reflog
8f151d7 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
2be3461 HEAD@{1}: commit: feina que creia perduda
8f151d7 (HEAD -> main) HEAD@{2}: commit (initial): primer commit
```
Cada línia és un estat anterior del HEAD. Quan localitzis el commit que vols (per exemple `2be3461`, el que crèiem perdut), el pots recuperar tornant la branca a aquell punt:
```shell
git reset --hard 2be3461 # torna la branca a aquell commit
```
O, si només vols mirar-lo sense moure la branca, fes `git switch --detach 2be3461`.
Compte: el reflog és local i no és etern (git el va netejant; per defecte, les entrades caduquen al cap d'uns 90 dies). És una xarxa de seguretat, no un substitut de fer commits i push sovint.
## M'ha sortit un editor que no sé com tancar
Si fas un `git commit` sense `-m`, o git necessita que escriguis un missatge (per exemple, en completar un merge), obre un editor de text. Per defecte sol ser **vim** o **nano**, i és fàcil quedar-s'hi encallat:
***vim**: prem `Esc`, escriu `:wq` i prem `Enter` per desar i sortir (o `:q!` per sortir sense desar).
***nano**: prem `Ctrl+O` i `Enter` per desar, i després `Ctrl+X` per sortir.
Per evitar-ho, posa el missatge directament a la comanda amb `-m`:
```shell
git commit -m"el missatge"
```
O configura un editor que et resulti més còmode:
```shell
git config --global core.editor "nano"# o "vim"
git config --global core.editor "code --wait"# VS Code
```
## Referències
*[Pro Git book (gratuït)](https://git-scm.com/book/en/v2)