Salta el contingut
 

Reset

Joan Puigcerver Ibáñez

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Reset (git reset)

L'ordre git reset permet moure la referència de la branca actual a qualsevol altre commit del repositori. Això significa que es pot modificar la història del repositori local per ajustar-la o refer-la segons les necessitats. Per exemple, permet:

  • Desfer o modificar commits anteriors: per corregir errors abans de compartir-los.
  • Reorganitzar els commits abans de publicar-los: per deixar una història més neta.
  • Moure els punters de les branques: per situar una branca en un altre commit.

git reset modifica la història del repositori i això pot ser perillós.

Sobretot en les branques que ja s'han publicat (push), ja que pot ocasionar problemes a la resta de persones que col·laboren en el repositori.

Funcionament de git reset Funcionament de git reset

Figura 1. Funcionament de git reset.

En moure la referència d'una branca, es poden deixar enrere commits amb els seus canvis. Com es gestionen aquests canvis depén del mode amb què s'executa l'ordre git reset:

  • --soft: els canvis es conserven en l'Àrea de preparació.
  • --mixed: els canvis es conserven en el Directori de treball. És el comportament per defecte.
  • --hard: els canvis es descarten.

Resum de la ferramenta git reset Resum de la ferramenta git reset

Figura 2. Resum de la ferramenta git reset.

A més, aquesta ordre pot provocar que alguns commits perden totes les referències i que, per tant, el recol·lector de fem de Git els esborre. Per exemple, en la Figura 1, els commits Canvi B i Canvi C s'esborraran perquè han perdut totes les referències.

Preparació del repositori

El repositori dels exemples es prepara amb les ordres següents:

setup_reset.sh
#!/bin/bash

# Elimina els repositoris si existeixen
if [ -d ~/git_reset ]; then
    rm -rf ~/git_reset
fi

mkdir -p ~/git_reset
cd ~/git_reset
git init
git branch -m main
echo "# Git reset i commit --amend" > README.md
git add README.md
git commit -m "Commit inicial"
echo "- Canvi A" >> README.md
git commit -a -m "Canvi A"
echo "- Canvi B" >> README.md
git commit -a -m "Canvi B"
echo "- Canvi C" >> README.md
git commit -a -m "Canvi C"
git lga
jpuigcerver@fp:~ $ mkdir -p ~/git_reset
jpuigcerver@fp:~ $ cd ~/git_reset
jpuigcerver@fp:~/git_reset $ git init
Initialized empty Git repository in ~/git_reset/.git/
jpuigcerver@fp:~/git_reset $ git branch -m main
jpuigcerver@fp:~/git_reset $ echo "# Git reset i commit --amend" > README.md
jpuigcerver@fp:~/git_reset $ git add README.md
jpuigcerver@fp:~/git_reset $ git commit -m "Commit inicial"
[main (root-commit) 5f92181] Commit inicial
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
jpuigcerver@fp:~/git_reset $ echo "- Canvi A" >> README.md
jpuigcerver@fp:~/git_reset $ git commit -a -m "Canvi A"
[main ff64d47] Canvi A
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_reset $ echo "- Canvi B" >> README.md
jpuigcerver@fp:~/git_reset $ git commit -a -m "Canvi B"
[main 8999e85] Canvi B
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_reset $ echo "- Canvi C" >> README.md
jpuigcerver@fp:~/git_reset $ git commit -a -m "Canvi C"
[main 99d1cc1] Canvi C
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_reset $ git lga
* 99d1cc1 - (0 seconds ago) Canvi C - Joan Puigcerver (HEAD -> main)
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

Crea el nou repositori en una carpeta independent per evitar problemes amb els exemples i exercicis anteriors.

Sintaxi general

L'ordre git reset mou la referència de la branca actual, on es troba el HEAD. La sintaxi és:

git reset [--soft | --mixed | --hard | --keep] <ref>
  • [--soft | --mixed | --hard | --keep]: (opcional) mode de funcionament, que s'explica en els apartats següents. Per defecte, --mixed.
  • <ref>: referència a la qual es mou la branca. Pot ser l'identificador d'un commit, una branca o una etiqueta.

Documentació oficial: git reset – Git

Soft

El mode --soft mou la referència de la branca actual al commit especificat i conserva en l'Àrea de preparació els canvis dels commits que es deixen enrere.

git reset --soft <ref>
Exemple: reset --soft

Es mou la referència de la branca main al commit Canvi B. Els canvis del commit Canvi C es conserven en l'Àrea de preparació.

jpuigcerver@fp:~/git_reset $ git reset --soft 8999e85
jpuigcerver@fp:~/git_reset $ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   README.md

jpuigcerver@fp:~/git_reset $ git diff --staged
diff --git a/README.md b/README.md
index dc7fc7d..d05d0d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
 # Git reset i commit --amend
 - Canvi A
 - Canvi B
+- Canvi C
jpuigcerver@fp:~/git_reset $ git lga
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver (HEAD -> main)
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

A continuació, es torna a crear el commit Canvi C.

jpuigcerver@fp:~/git_reset $ git commit -m "Canvi C"
[main 99d1cc1] Canvi C
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_reset $ git lga
* 99d1cc1 - (0 seconds ago) Canvi C - Joan Puigcerver (HEAD -> main)
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

Mixed

El mode --mixed mou la referència de la branca actual al commit especificat i conserva els canvis en el Directori de treball. És el comportament per defecte si no s'especifica cap mode.

git reset --mixed <ref>
Exemple: reset --mixed

Es mou la referència de la branca main al commit Canvi B. Els canvis del commit Canvi C es conserven en el Directori de treball.

jpuigcerver@fp:~/git_reset $ git reset --mixed 8999e85
Unstaged changes after reset:
M   README.md
jpuigcerver@fp:~/git_reset $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_reset $ git diff
diff --git a/README.md b/README.md
index dc7fc7d..d05d0d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
 # Git reset i commit --amend
 - Canvi A
 - Canvi B
+- Canvi C
jpuigcerver@fp:~/git_reset $ git lga
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver (HEAD -> main)
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

A continuació, es torna a crear el commit Canvi C.

jpuigcerver@fp:~/git_reset $ git add README.md
jpuigcerver@fp:~/git_reset $ git commit -m "Canvi C"
[main 99d1cc1] Canvi C
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_reset $ git lga
* 99d1cc1 - (0 seconds ago) Canvi C - Joan Puigcerver (HEAD -> main)
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

Hard

El mode --hard mou la referència de la branca actual al commit especificat i torna tot el repositori a l'estat d'aquesta referència.

git reset --hard <ref>

Tots els canvis es descarten permanentment.

Exemple: reset --hard

Es mou la referència de la branca main al commit Canvi B. Els canvis del commit Canvi C no es conserven enlloc i no es poden recuperar.

jpuigcerver@fp:~/git_reset $ git reset --hard 8999e85
HEAD is now at 8999e85 Canvi B
jpuigcerver@fp:~/git_reset $ git status
On branch main
nothing to commit, working tree clean
jpuigcerver@fp:~/git_reset $ git lga
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver (HEAD -> main)
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

Keep

El mode --keep és molt semblant al comportament per defecte. La diferència és que no permet fer el reset si això implica sobreescriure els canvis actuals del Directori de treball.

git reset --keep <ref>
Exemple: reset --keep

Es prova de moure la referència de la branca actual amb canvis pendents en el Directori de treball.

jpuigcerver@fp:~/git_reset $ echo "- Canvi C" >> README.md
jpuigcerver@fp:~/git_reset $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_reset $ git reset --keep ff64d47
error: Entry 'README.md' not uptodate. Cannot merge.
fatal: Could not reset index file to revision 'ff64d47'.
jpuigcerver@fp:~/git_reset $ git lga
* 8999e85 - (0 seconds ago) Canvi B - Joan Puigcerver (HEAD -> main)
* ff64d47 - (0 seconds ago) Canvi A - Joan Puigcerver
* 5f92181 - (0 seconds ago) Commit inicial - Joan Puigcerver

S'observa que, com que el reset sobreescriuria els canvis del Directori de treball, l'operació no es fa.

Bibliografia

📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.