A la lliçó 03-02 ens vam trobar per primera vegada amb aquest missatge:
error: Your local changes to the following files would be overwritten by checkout: app.js Please commit your changes or stash them before you switch branches.
I vam dir que hi havia una tercera sortida, a més de confirmar o descartar: apartar els canvis. Vam prometre una lliçó sencera. És aquesta.
git stash és el calaix de sastre de Git: agafa tot el que tens a mitges al directori de treball i a l'índex, ho desa en un lloc segur, i et deixa la còpia de treball neta com si acabessis de clonar. Després, quan vulguis, ho recuperes.
L'escenari és sempre el mateix i li passa a tothom: estàs a mitja feina, amb codi que no compila i que no mereix un commit, i arriba una urgència. La Carla ho viurà en aquesta lliçó. I al final veurem el que gairebé ningú mira: que el stash no té res de màgic, que per dins són commits normals en una referència amagada, exactament els mateixos objectes del model de dades de la lliçó 01-04.
Contingut
- L'escenari: la Carla i la urgència
git stash: què desa i què no- Fitxers sense seguiment i ignorats:
-ui-a - La pila:
list,show,apply,pop,drop,clear applydavant depop- Referir-se a una entrada concreta
git stash push: missatges, rutes i mode interactiu--keep-indexi--stagedgit stash branch: quan el stash ja no encaixa- Com funciona per dins
- Riscos: stashes oblidats i falses còpies de seguretat
- L'escenari: la Carla i la urgència
La Carla és a funcionalitat/ordre-per-data, a mitja funció. Ha tocat app.js i estils.css, i ha creat un fitxer nou, utilitats.js, que encara no ha afegit al repositori.
Arriba un missatge de l'Ana: el botó d'esborrar no funciona en producció i cal corregir-ho ja. La Carla necessita canviar a main, fer la correcció i tornar. Les seves opcions:
| Opció | Problema |
|---|---|
Confirmar un wip |
Embruta l'historial (encara que sigui corregible amb 05-02), i el seu codi no compila |
Descartar amb git restore |
Perd dues hores de feina |
Copiar els fitxers a /tmp a mà |
Funciona, però és artesania i s'oblida |
git stash |
Aparta-ho tot, deixa el directori net i el torna després |
Saved working directory and index state On funcionalitat/ordre-per-data: Ordenació per data a mitges
Directori net. La Carla pot canviar de branca sense que Git protesti, corregir la fallada, publicar-la i tornar:
git switch main
git pull
# ... corregeix, confirma, publica ...
git switch funcionalitat/ordre-per-data
git stash popOn branch funcionalitat/ordre-per-data
Changes not staged for commit:
modified: app.js
modified: estils.css
Untracked files:
utilitats.js
Dropped refs/stash@{0} (a7f3c92e8b1d5c4a7f2e9b6d3c8a1f5e7b4d2c9a)Tot torna a estar com estava. Això és git stash en el seu ús més bàsic. Ara, els detalls que marquen la diferència.
git stash: què desa i què no
git stash: què desa i què nogit stash sense arguments és un àlies de git stash push. Per defecte desa:
- Els canvis en fitxers amb seguiment que estan modificats al directori de treball.
- Els canvis en fitxers amb seguiment que estan preparats a l'índex.
I no desa:
- Els fitxers sense seguiment (els que apareixen com a
??agit status). - Els fitxers ignorats pel
.gitignore.
Aquest és el primer parany, i és greu. Si la Carla hagués fet git stash sense -u:
app.js i estils.css estarien apartats, però utilitats.js continuaria allà, sense seguiment i sense apartar. I com que no l'aparta, tampoc no el torna: si la Carla l'esborrés per error pensant que és al stash, el perdria.
La lògica de Git té sentit —un fitxer sense seguiment mai no ha format part del repositori, així que Git és conservador i no el toca— però la conseqüència pràctica sorprèn sempre la primera vegada.
Recordant les tres zones de la lliçó 01-03, el repartiment és aquest:
| Zona | S'aparta amb git stash? |
|---|---|
| Directori de treball, fitxers amb seguiment modificats | Sí |
| Índex (àrea de preparació) | Sí |
| Fitxers sense seguiment | Només amb -u |
| Fitxers ignorats | Només amb -a |
| Repositori (commits) | Mai: el stash no toca commits |
I un matís que importa en recuperar: per defecte, el stash no conserva què estava preparat i què no. En fer pop o apply, tot torna com a "modificat sense preparar". Si necessites conservar aquesta distinció, existeix --index:
Amb --index, el que era a l'índex torna a l'índex. Pot fallar si l'estat actual no ho permet, cas en què Git ho aplica tot sense preparar i t'avisa.
- Fitxers sense seguiment i ignorats:
-u i -a
-u i -a| Opció | Nom llarg | Què afegeix al que es desa per defecte |
|---|---|---|
-u |
--include-untracked |
Els fitxers sense seguiment |
-a |
--all |
Els sense seguiment i els ignorats |
Sobre -a: els fitxers ignorats solen ser node_modules/, dist/, .env, fitxers de compilació... Apartar-los significa esborrar-los del directori de treball i ficar-los al stash. Amb node_modules/ això són desenes de milers de fitxers i una operació lentíssima. I amb .env, les teves credencials locals passen a estar dins d'objectes de Git, que és just el que no vols. Fes servir -a de manera excepcional i conscient.
En canvi, -u és tan sovint el que vols que molta gent el configura com a comportament per defecte mitjançant un àlies:
Els àlies es veuen a fons a la lliçó 06-04, però aquest val la pena des d'ara mateix.
- La pila:
list, show, apply, pop, drop, clear
list, show, apply, pop, drop, clearEl stash no és un calaix únic: és una pila. Pots apartar diverses vegades, i cada entrada nova es col·loca a sobre.
stash@{0}: On funcionalitat/ordre-per-data: Ordenació per data a mitges
stash@{1}: WIP on main: 7d3a8f4 Retorna el focus al camp de text després d'esborrar
stash@{2}: On funcionalitat/etiquetes-color: prova del selectorstash@{0}és sempre la més recent.- Els números es renumeren cada vegada que afegeixes o treus una entrada. El
stash@{1}d'avui no és el mateix que el de demà. És un motiu excel·lent per posar missatges descriptius. - El text
WIP on main: 7d3a8f4 ...és el missatge automàtic quan no n'hi poses cap: la branca i el commit sobre el qual es va desar.
Per veure el contingut d'una entrada:
diff --git a/app.js b/app.js
index 8c3d5a1..2e7b9f4 100644
--- a/app.js
+++ b/app.js
@@ -22,7 +22,11 @@ function pintaLlista() {
const llista = document.getElementById('llista-tasques');
llista.innerHTML = '';
- tasques.forEach(function (t) {
+ const ordenades = tasques.slice().sort(function (a, b) {
+ return b.creada - a.creada;
+ });
+ ordenades.forEach(function (t) {
llista.appendChild(creaElementTasca(t));
});Un detall: per defecte, git stash show no inclou els fitxers sense seguiment que haguessis desat amb -u. Per veure'ls:
El repertori complet d'ordres:
| Ordre | Què fa |
|---|---|
git stash / git stash push |
Aparta els canvis i neteja el directori |
git stash list |
Llista la pila |
git stash show [-p] [<entrada>] |
Ensenya què hi ha en una entrada |
git stash apply [<entrada>] |
Aplica els canvis conservant l'entrada |
git stash pop [<entrada>] |
Aplica els canvis i elimina l'entrada |
git stash drop [<entrada>] |
Elimina l'entrada sense aplicar-la |
git stash clear |
Buida la pila sencera. Sense confirmació |
git stash branch <branca> [<entrada>] |
Crea una branca a partir de l'entrada i l'aplica |
git stash create |
Crea l'objecte de stash sense tocar la pila ni el directori |
git stash store <sha> |
Desa a la pila un objecte creat amb create |
git stash clear mereix un avís en negreta: esborra tota la pila de cop i no pregunta. Recuperar-ne alguna cosa després és possible però empipador (cal remenar objectes orfes amb git fsck, tècnica de la lliçó 09-04). Tracta'l com un rm -rf.
apply davant de pop
apply davant de popTotes dues apliquen els canvis desats sobre el teu directori de treball. La diferència és què passa amb l'entrada després:
git stash apply |
git stash pop |
|
|---|---|---|
| Aplica els canvis | Sí | Sí |
| Elimina l'entrada de la pila | No | Sí, si l'aplicació va tenir èxit |
| Es pot aplicar en diverses branques | Sí | No (desapareix després del primer) |
| Si hi ha conflicte | L'entrada es conserva | L'entrada es conserva |
| Risc de duplicar canvis | Sí, si oblides fer drop |
No |
| Risc de perdre el desament | No | Baix, però existeix |
En què es tradueix això a la pràctica:
Fes servir pop en el cas normal: vas apartar, vas fer una altra cosa, tornes. És una sola ordre i deixa la pila neta.
Fes servir apply quan:
- Vols aplicar els mateixos canvis en dues branques diferents.
- No estàs segur que encaixin i prefereixes conservar la còpia fins a comprovar-ho.
- La branca actual ha canviat molt i sospites que hi haurà conflicte.
El detall que salva vides: si pop provoca un conflicte, l'entrada NO s'elimina. Git aplica el que pot, deixa els marcadors de conflicte i conserva el stash per si de cas. És un comportament deliberat i molt assenyat. Però té una conseqüència molesta: després de resoldre el conflicte, l'entrada continua a la pila i l'has d'esborrar tu:
Auto-merging app.js CONFLICT (content): Merge conflict in app.js The stash entry is kept in case you need it again.
# Resoldre el conflicte (mecànica de la lliçó 03-05)
# ... editar app.js, treure els marcadors ...
git add app.js
# I ara sí, eliminar l'entrada a mà
git stash dropApunta't aquest hash que imprimeix drop. És la referència a l'objecte del stash, i amb ell es pot recuperar una entrada esborrada per error (lliçó 09-04). És el mateix consell que vam donar en esborrar branques a 03-06, i pel mateix motiu.
Un avís sobre els conflictes de stash: a diferència d'una fusió o d'un rebase, aquí no hi ha --abort. Si pop conflictua, ets enmig de la resolució i l'única manera de tornar enrere és descartar els canvis del directori de treball (git checkout -- . o git reset --hard, amb la cura que això exigeix) sabent que el stash continua estalvi a la pila.
- Referir-se a una entrada concreta
Gairebé totes les ordres accepten una entrada. Si l'omets, es fa servir stash@{0}.
La notació stash@{N} és la mateixa sintaxi de reflog que vas veure a 02-06 aplicada a la referència refs/stash. I admet formes per temps:
En alguns intèrprets d'ordres les claus necessiten cometes o escapament:
Des de Git 2.11 també s'admet el número a seques, que és més còmode:
I recorda: els números es renumeren. Si tens tres entrades i esborres la del mig, la que era stash@{2} passa a ser stash@{1}. No desis mai un número apuntat en un paper; desa el missatge.
git stash push: missatges, rutes i mode interactiu
git stash push: missatges, rutes i mode interactiugit stash push és la forma moderna i completa. git stash save "missatge" és la forma antiga, encara funciona, però està desaconsellada i no admet rutes.
Missatge descriptiu:
És la millora de qualitat de vida més barata que existeix amb aquesta eina. Un git stash list amb tres entrades anomenades WIP on main és inútil; amb tres missatges descriptius, és un pla de treball.
Desar només unes rutes:
git stash push -m "Només els estils" estils.css
git stash push -m "Tot el del directori d'informes" informes/Els canvis d'aquests fitxers s'aparten; la resta es queda al directori de treball. És molt útil quan has barrejat dues tasques a la mateixa sessió i en vols separar una per treballar amb l'altra tranquil.
Mode interactiu:
Fragment a fragment, igual que git add -p (lliçó 02-04), Git et pregunta per cada bloc de canvis si el vols apartar:
@@ -22,7 +22,11 @@ function pintaLlista() {
const llista = document.getElementById('llista-tasques');
llista.innerHTML = '';
- tasques.forEach(function (t) {
+ const ordenades = tasques.slice().sort(function (a, b) {
...
(1/3) Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]?Les tecles són les mateixes de sempre: y sí, n no, q sortir, s dividir el fragment, e editar-lo a mà.
Altres opcions de push:
| Opció | Què fa |
|---|---|
-m <missatge> |
Missatge descriptiu |
-u / -a |
Incloure sense seguiment / també ignorats |
-p |
Triar fragment a fragment |
-k / --keep-index |
Deixa intacte el que estava preparat (apartat 8) |
-S / --staged |
Aparta només el que està preparat (apartat 8) |
-q |
Silenciós |
--pathspec-from-file=<f> |
Llegeix la llista de rutes d'un fitxer |
--keep-index i --staged
--keep-index i --stagedDues opcions semblants de nom i molt diferents d'efecte. La taula ho aclareix tot; suposem que tens app.js preparat i estils.css modificat sense preparar:
| Opció | Què es desa al stash | Què queda al directori de treball |
|---|---|---|
| (cap) | app.js + estils.css |
Res: directori net |
--keep-index |
app.js + estils.css |
app.js preparat (la resta, net) |
--staged |
Només app.js |
estils.css modificat |
--keep-index desa tot però restaura al directori el que era a l'índex. El seu ús clàssic és provar un commit abans de fer-lo:
# Tinc preparat exactament el que vull confirmar
git add app.js
git stash push --keep-index -m "El que no va en aquest commit"
# El directori conté NOMÉS el que confirmaré: puc provar-ho de debò
npm test
# Si passa, confirmo amb la seguretat d'haver provat això i només això
git commit -m "Afegeix l'ordenació per data de creació"
# I recupero la resta
git stash popÉs la manera correcta d'assegurar-se que un commit és autocontingut i no depèn de canvis que s'han quedat fora. Molta gent descobreix així que el seu commit "llest" no compilava per si sol.
Nota: amb
--keep-index, el stash conté també el que estava preparat. En ferpopdesprés del commit, aquests canvis ja estan confirmats i poden conflictuar. A la pràctica se sol combinar amb--include-untrackedi s'accepta que elpopposterior de vegades requereix un--skipmental: revisa ambgit stash show -pabans de recuperar.
--staged (des de Git 2.35) és més simple i més nova: aparta només el que és a l'índex i deixa la resta. És el contrari del cas anterior, i serveix per a "això que ja tenia preparat me l'enduc a una altra branca":
git add utilitats.js
git stash push --staged -m "La utilitat va en una altra branca"
git switch funcionalitat/utilitats
git stash pop
git stash branch: quan el stash ja no encaixa
git stash branch: quan el stash ja no encaixaProblema clàssic: vas desar un stash fa tres dies, la branca ha avançat molt des de llavors i ara git stash pop dona un conflicte rere l'altre.
La causa és que el stash es va desar sobre un commit concret i ara s'està aplicant sobre un altre de completament diferent. La solució és aplicar-lo on encaixava:
Aquesta ordre fa quatre coses alhora:
- Crea una branca nova al commit sobre el qual es va desar el stash.
- Es canvia a ella.
- Aplica el stash (que encaixa perfectament, perquè el context és l'original).
- Elimina l'entrada de la pila, ja que s'ha aplicat amb èxit.
Switched to a new branch 'funcionalitat/rescat'
On branch funcionalitat/rescat
Changes not staged for commit:
modified: app.js
Dropped refs/stash@{1} (5c8e2d1f9a3b7e4c6d1f8a2b5e9c3d7f4a1b8e6c)Des d'aquí pots confirmar tranquil·lament i després integrar la branca amb merge o rebase, resolent els conflictes una sola vegada i amb context, en lloc de barallar-te amb un pop a cegues.
És la millor sortida quan un stash "no entra". I també la millor manera de convertir un stash que s'ha tornat important en feina de debò.
- Com funciona per dins
Aquí és on el stash deixa de semblar màgia. Reprenem el model de dades de la lliçó 01-04.
Quan fas git stash, Git crea commits normals:
- Un commit amb l'estat de l'índex.
- Opcionalment, un commit amb els fitxers sense seguiment (si has fet servir
-u). - Un commit de fusió el primer pare del qual és el
HEADactual, el segon el commit de l'índex, i el tercer (si existeix) el dels sense seguiment. Aquest és el commit del stash.
I desa la referència a aquest commit a refs/stash. Comprovem-ho:
Un commit corrent. Vegem-ne l'interior amb les mateixes eines de 01-04:
tree 3f8b1c7e2d9a5b4f6c1e8a3d7b2f5c9e4a1d6b8f parent 7d3a8f4c9b1e5d2a8f7c3b6e9d4a1c8f5b2e7d3a parent 8e2c5f1a9d3b7e4c1f6a8d2b5e9c3f7a4d1b8e6c parent 1c9e4b7f2a8d5c3e6b1f9a4d7c2e5b8f3a6d1c9e author Carla Vidal <[email protected]> 1753959200 +0200 committer Carla Vidal <[email protected]> 1753959200 +0200 On funcionalitat/ordre-per-data: Prova d'anatomia
Tres pares:
| Pare | Què conté |
|---|---|
1r (7d3a8f4) |
El HEAD de quan vas desar: la base |
2n (8e2c5f1) |
L'estat de l'índex |
3r (1c9e4b7) |
Els fitxers sense seguiment (només amb -u) |
I el tree del commit mateix és l'estat del directori de treball. Amb aquests quatre arbres, Git pot reconstruir exactament el que tenies i aplicar-ho com una fusió a tres bandes. D'aquí que els conflictes de stash pop siguin conflictes de fusió normals i corrents.
La pila, per la seva banda, és el reflog de refs/stash:
a7f3c92 stash@{0}: On funcionalitat/ordre-per-data: Prova d'anatomia
5c8e2d1 stash@{1}: WIP on main: 7d3a8f4 Retorna el focus al camp de text
9b4f7e3 stash@{2}: On funcionalitat/etiquetes-color: prova del selectorAixò explica de cop tres coses que abans semblaven arbitràries:
- Per què la sintaxi és
stash@{N}: és exactament la sintaxi del reflog. - Per què els números es renumeren: són posicions en un registre, no identificadors.
- Per què es poden recuperar stashes esborrats: l'objecte continua a la base de dades fins que passi el recol·lector d'escombraries.
I una conseqüència pràctica molt útil: com que el stash és un commit, pots fer servir qualsevol ordre de commits amb ell.
git show stash@{0} # el commit del stash
git diff stash@{0}^ stash@{0} # el seu diff contra la base
git diff main stash@{0} -- app.js # comparar amb una altra branca
git log --oneline stash@{0}^..stash@{0} # rangs, encara que aquí aporti poc
- Riscos: stashes oblidats i falses còpies de seguretat
Risc 1: el stash oblidat. És, de bon tros, el problema més freqüent. Apartes alguna cosa, la urgència s'allarga, passen tres setmanes i la feina continua allà. Quan la trobes, ja no encaixa amb res.
El stash no apareix a git status, no apareix a git log, no surt en cap interfície gràfica per defecte i no s'envia mai al servidor. És invisible.
Mesures:
# Mira la pila de tant en tant
git stash list
# Millor: afegeix-ho al missatge del teu prompt o a un àlies que facis servir a diari
git config --global alias.st '!git status && echo "--- stash ---" && git stash list'I la mesura real: el stash és per a minuts o hores, no per a dies. Si la feina ha d'esperar més d'una jornada, és una branca. git stash branch està just per a això.
Risc 2: creure que és una còpia de seguretat. No ho és, per tres motius:
- És local. No s'envia mai amb
git push. El refspec per defecte només cobreixrefs/heads/*(lliçó 04-05), irefs/stashen queda fora. Si se't mor el disc, el stash mor amb ell. - No es clona.
git cloneno porta els stashes de ningú. Ni tan sols ungit clone --mirrorels replica de manera útil. - És fràgil.
git stash clearho esborra tot sense preguntar. I els commits del stash, en no estar referenciats per cap branca, són candidats al recol·lector d'escombraries quan s'esborren de la pila.
Una còpia de seguretat de debò és un commit en una branca publicada. Si la feina importa, confirma-la —encara que sigui amb un missatge provisional que després arreglaràs amb rebase -i (lliçó 05-02)— i publica-la.
Risc 3: aplicar el stash a la branca equivocada. El stash no està lligat a cap branca: pots fer pop a qualsevol. De vegades és exactament el que vols (moure't de branca amb la feina a coll); de vegades és un accident que omple main de canvis que no li tocaven. git stash list et diu en quina branca es va desar cada entrada; llegeix-ho abans de recuperar.
Risc 4: els fitxers sense seguiment. Ja ho hem vist: sense -u no es desen. L'error concret i perillós és fer git stash seguit de git clean -fd per "deixar-ho tot net": el clean esborra els fitxers sense seguiment que el stash no va desar, i aquests sí que es perden de debò.
Errors Habituals i Consells
Error 1: git stash sense -u quan hi ha fitxers nous. Es queden fora. És la sorpresa número u amb aquesta eina. Mira sempre git status --short abans d'apartar.
Error 2: git stash clear per "endreçar". Esborra tota la pila sense preguntar i sense confirmació. Fes servir git stash drop <entrada> d'una en una, després de mirar cadascuna amb show -p.
Error 3: pensar que pop sempre elimina l'entrada. Si hi ha conflicte, la conserva expressament. Després de resoldre, has de fer git stash drop tu.
Error 4: acumular stashes sense missatge. Cinc entrades anomenades WIP on main són cinc incògnites. git stash push -m "..." sempre.
Error 5: fer servir el stash com a sistema de branques. Si trigaràs més d'una jornada, fes una branca. El stash no sobreviu a la memòria de ningú.
Error 6: fiar-se dels números. stash@{2} canvia de significat tan bon punt afegeixes o treus entrades. Identifica per missatge, no per número.
Error 7: combinar git stash amb git clean -fd sense pensar. El primer no desa el que està sense seguiment; el segon ho esborra. La combinació destrueix fitxers nous.
Consell 1: àlies amb -u incorporat. git config --global alias.desa 'stash push -u -m' i a partir d'aquí git desa "el que sigui".
Consell 2: --keep-index abans de confirmar. Un git stash push --keep-index && npm test et diu si el teu commit és realment autocontingut. Es triga un minut i evita commits trencats.
Consell 3: git stash show -p abans de pop. Especialment si l'entrada té més d'un dia. Saber què arribarà evita ensurts.
Consell 4: git stash branch tan bon punt hi hagi conflicte. No et barallis amb un pop que no encaixa: crea la branca al punt original, aplica netament i fusiona amb calma.
Consell 5: revisa la pila els divendres. Un git stash list setmanal és suficient perquè no se't quedi res tres mesos.
Exercicis
Exercici 1: el parany dels fitxers sense seguiment
En un repositori de proves:
- Modifica un fitxer amb seguiment i crea'n un de nou sense afegir.
- Fes
git stashsense-ui comprova ambgit statusquè ha passat amb cadascun. - Recupera, i repeteix l'operació amb
-u. - Demostra amb
git stash show -p -uque en el segon cas el fitxer nou sí que és a dins.
Exercici 2: --keep-index per validar un commit
Prepara un escenari on tinguis dos canvis: un de preparat (que compila per si sol) i un altre sense preparar (que trenca el fitxer). Fent servir --keep-index:
- Aparta el que no va al commit.
- Comprova que el fitxer és vàlid (
node --checko similar). - Confirma.
- Recupera la resta i observa què passa.
Exercici 3: anatomia d'un stash
Crea un stash amb -u i demostra amb ordres de baix nivell:
- Que
refs/stashapunta a un commit. - Que aquest commit té tres pares.
- Què conté cadascun dels tres.
- Que
git reflog stashigit stash listmostren la mateixa informació.
Solucions
Solució 1:
mkdir /tmp/practica-stash && cd /tmp/practica-stash
git init -b main
echo "original" > seguit.txt && git add . && git commit -m "Base"
echo "modificat" > seguit.txt
echo "soc nou" > sense-seguir.txt
git status --shortseguit.txt ha tornat a la seva versió original; sense-seguir.txt continua exactament on era. No s'ha desat.
Ara sí: el directori està net de debò i el fitxer nou ha desaparegut (és al stash).
diff --git a/seguit.txt b/seguit.txt
--- a/seguit.txt
+++ b/seguit.txt
@@ -1 +1 @@
-original
+modificat
diff --git a/sense-seguir.txt b/sense-seguir.txt
new file mode 100644
--- /dev/null
+++ b/sense-seguir.txt
@@ -0,0 +1 @@
+soc nouSolució 2:
mkdir /tmp/practica-keepindex && cd /tmp/practica-keepindex
git init -b main
echo "const a = 1;" > app.js && git add . && git commit -m "Base"
# Canvi bo, preparat
echo "const b = 2;" >> app.js
git add app.js
# Canvi dolent, sense preparar
echo "const c = ;" >> app.js
git status --short(La doble M significa: modificat a l'índex i modificat a més al directori de treball.)
El fitxer conté només el que estava preparat.
El pop ha tornat l'estat complet que hi havia abans. Com que el commit ja conté la línia de b, en aquest cas simple no hi ha conflicte; amb canvis que se solapen a les mateixes línies sí que n'hi hauria, i és la raó per la qual convé revisar amb git stash show -p abans.
Solució 3:
mkdir /tmp/practica-anatomia && cd /tmp/practica-anatomia
git init -b main
echo "base" > f.txt && git add . && git commit -m "Base"
echo "canvi al directori" > f.txt
echo "preparat" > g.txt && git add g.txt
echo "sense seguir" > h.txt
git stash push -u -m "Anatomia"parent 4b8e1c7f2a9d5e3b6c1f8a4d7b2e5c9f3a6d1b8e parent 9d2f6a3c8b1e5f7d4a2c9e6b3f8d1a5c7e4b2f9d parent 6c1a8f4d3e7b2c5a9f1d6b8e3c7a4f2d5b9e1c8a
# 3. Què conté cadascun
git show --stat refs/stash^1 | head -3 # la base: el commit HEAD original
git ls-tree refs/stash^2 # l'índex: inclou g.txt preparat
git ls-tree refs/stash^3 # els sense seguiment: h.txtLa mateixa informació, presentada de dues maneres. git stash list és, literalment, una vista del reflog de refs/stash.
Conclusió
git stash és una eina petita amb més matisos dels que aparenta. L'essencial:
- Aparta els canvis sense confirmar i deixa el directori net, perquè puguis canviar de branca, atendre una urgència o provar alguna cosa, i recuperar-los després.
- Per defecte NO desa els fitxers sense seguiment ni els ignorats: per a això hi ha
-u(sense seguiment, l'opció que voldràs gairebé sempre) i-a(també els ignorats, que només es fa servir molt conscientment). - És una pila:
git stash listl'enumera,stash@{0}és la més recent i els números es renumeren, així que cal identificar per missatge.git stash push -m "..."és obligatori a la pràctica. popaplica i elimina;applyaplica i conserva. Si hi ha conflicte,popconserva l'entrada i has de ferdropa mà després de resoldre.--keep-indexdeixa al directori només el que anaves a confirmar (per provar-ho de debò);--stagedaparta només el que està preparat. Ipush -ppermet triar fragment a fragment, ipush <ruta>apartar només uns fitxers.git stash branch <branca>crea una branca al commit original del stash i l'aplica allà: la millor sortida quan un stash ja no encaixa.- Per dins no hi ha màgia: són commits normals a
refs/stash, amb elHEADoriginal, l'índex i els sense seguiment com a pares, i la pila és el reflog d'aquesta referència. D'aquí venen la sintaxistash@{N}i la renumeració. - No és una còpia de seguretat: és local, no s'envia, no es clona i
clearl'esborra sense preguntar. Per a minuts i hores, no per a dies.
El que ve
Fins aquí, tot el mòdul ha anat de modificar l'historial: reaplicar-lo, reorganitzar-lo, copiar-lo, apartar-lo. Ara farem el contrari: fixar-hi un punt per sempre.
gestor-tasques està a punt de tenir la seva primera versió estable. L'equip necessita poder dir "això és la 1.0.0" i que d'aquí a dos anys, quan arribi una incidència d'un client que continua amb aquella versió, algú pugui situar-se exactament en aquell codi sense dependre de recordar un hash de quaranta caràcters.
Per a això hi ha les etiquetes, el quart tipus d'objecte de la base de dades de Git que vam conèixer a la lliçó 01-04 i del qual amb prou feines hem parlat. Ho veiem a la lliçó 05-05: Etiquetant Confirmacions.
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ó
