Salta el contingut
 

Revert i cherry-pick

Autor: Joan Puigcerver Ibáñez

Correu electrònic: j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Introducció

Les accions revert i cherry-pick són eines poc comuns, però poden ser útils en situacions específiques.

Preparació repositori
setup_cherrypick.sh
#!/bin/bash

# Elimina els repositori si existeix
if [ -d ~/git_cherrypick ]; then
    rm -rf ~/git_cherrypick
fi

mkdir -p ~/git_cherrypick
cd ~/git_cherrypick
git init
git branch -m main
echo "# Git revert i cherrypick" > 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"
echo "- Canvi D" >> README.md
git commit -a -m "Canvi D"
echo "- Canvi E" >> README.md
git commit -a -m "Canvi E"
git lga
jpuigcerver@fp:~ $ mkdir -p ~/git_cherrypick
jpuigcerver@fp:~ $ cd ~/git_cherrypick
jpuigcerver@fp:~/git_cherrypick $ git init
Initialized empty Git repository in ~/git_cherrypick/.git/
jpuigcerver@fp:~/git_cherrypick (main) $ git branch -m main
jpuigcerver@fp:~/git_cherrypick (main) $ echo "# Git revert i cherrypick" > README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git add README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git commit -m "Commit inicial"
[main (root-commit) 810ec42] Commit inicial
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
jpuigcerver@fp:~/git_cherrypick (main) $ echo "- Canvi A" >> README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git commit -a -m "Canvi A"
[main 4d18d71] Canvi A
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ echo "- Canvi B" >> README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git commit -a -m "Canvi B"
[main fad1ea7] Canvi B
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ echo "- Canvi C" >> README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git commit -a -m "Canvi C"
[main 75f51e1] Canvi C
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ echo "- Canvi D" >> README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git commit -a -m "Canvi D"
[main a079d5b] Canvi D
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ echo "- Canvi E" >> README.md
jpuigcerver@fp:~/git_cherrypick (main) $ git commit -a -m "Canvi E"
[main ff4ae1c] Canvi E
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* ff4ae1c - (0 seconds ago) Canvi E - Joan Puigcerver (HEAD -> main)
* a079d5b - (0 seconds ago) Canvi D - Joan Puigcerver
* 75f51e1 - (0 seconds ago) Canvi C - Joan Puigcerver
* fad1ea7 - (0 seconds ago) Canvi B - Joan Puigcerver
* 4d18d71 - (0 seconds ago) Canvi A - Joan Puigcerver
* 810ec42 - (0 seconds ago) Commit inicial - Joan Puigcerver

Revert

La comanda revert és útil per desfer els canvis d'un commit concret, sense alterar la història del repositori.

El seu funcionament consisteix en crear un nou commit que inverteix els canvis del commit que desitgem desfer.

Documentació

Documentació oficial de git revert

La sintaxi és la següent:

git revert <ref>

  • <ref>: Referència del commit que es vol desfer.

Funcionament de git revert

Figura 1. Funcionament de git revert.

Exemple: git revert
jpuigcerver@fp:~/git_cherrypick (main) $ git revert ff4ae1c --no-edit
[main 2f610b9] Revert "Canvi E"
 Date: Sun Oct 20 22:15:45 2024 +0200
 1 file changed, 1 deletion(-)
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* 2f610b9 - (0 seconds ago) Revert "Canvi E" - Joan Puigcerver (HEAD -> main)
* ff4ae1c - (0 seconds ago) Canvi E - Joan Puigcerver
* a079d5b - (0 seconds ago) Canvi D - Joan Puigcerver
* 75f51e1 - (0 seconds ago) Canvi C - Joan Puigcerver
* fad1ea7 - (0 seconds ago) Canvi B - Joan Puigcerver
* 4d18d71 - (0 seconds ago) Canvi A - Joan Puigcerver
* 810ec42 - (0 seconds ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ git show
commit 2f610b93b6a0d1642dbc20585c964f4afee1fed5
Author: Joan Puigcerver <j.puigcerveribanez@edu.gva.es>
Date:   Sun Oct 20 22:15:45 2024 +0200

    Revert "Canvi E"

    This reverts commit ff4ae1c6f2b90276fdb9aa48415e631d74497811.

diff --git a/README.md b/README.md
index 9024074..ec78542 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,3 @@
 - Canvi B
 - Canvi C
 - Canvi D
-- Canvi E

Revertir múltiples commits

L'acció revert sols permet desfer un commit a la vegada.

En cas de voler desfer múltiples commits, es pot aplicar la comanda revert de forma successiva a cada commit que es vol desfer amb la opció --no-commit.

Aquest procés posarà el repositori en un estat REVERTING i afegira els canvis a l'Àrea de Preparació (Staging Area).

En aquest punt, es poden revertir més commits o finalitzar el procés amb git revert --continue.

git revert --no-commit <ref>
Exemple: git revert múltiples commits
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver (HEAD -> main)
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ git revert a079d5b --no-commit
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git diff --staged
diff --git a/README.md b/README.md
index ec78542..89461b7 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,3 @@
 - Canvi A
 - Canvi B
 - Canvi C
-- Canvi D
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git revert 75f51e1 --no-commit
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git diff --staged
diff --git a/README.md b/README.md
index ec78542..5377894 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
 # Git revert i cherrypick
 - Canvi A
 - Canvi B
-- Canvi C
-- Canvi D
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git commit -m "Revert \"Canvi C i D\"" # (1)!
[main aa99382] Revert "Canvi C i D"
 1 file changed, 2 deletions(-)
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver (HEAD -> main)
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ git show
commit aa9938270b80774ca3fd740649860c76c9fe9e4d
Author: Joan Puigcerver <j.puigcerveribanez@edu.gva.es>
Date:   Sun Oct 20 22:15:46 2024 +0200

    Revert "Canvi C i D"

diff --git a/README.md b/README.md
index ec78542..5377894 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
 # Git revert i cherrypick
 - Canvi A
 - Canvi B
-- Canvi C
-- Canvi D
  1. Per eixir de l'estat REVERTING també es pot fer un git commit.

Resolució de conflictes

Aquesta acció pot generar conflictes si els canvis que es volen desfer han estat modificats en commits posteriors.

En aquest cas, passarem a l'estat REVERTING i caldrà resoldre els conflictes manualment, de la mateixa manera que es fa en una fusió de branques (merge).

Exemple: Resolució de conflictes en git revert
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver (HEAD -> main)
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ git revert 4d18d71
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not revert 4d18d71... Canvi A
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git revert --continue".
hint: You can instead skip this commit with "git revert --skip".
hint: To abort and get back to the state before "git revert",
hint: run "git revert --abort".
hint: Disable this message with "git config advice.mergeConflict false"
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git status
On branch main
You are currently reverting commit 4d18d71.
  (fix conflicts and run "git revert --continue")
  (use "git revert --skip" to skip this patch)
  (use "git revert --abort" to cancel the revert operation)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
    both modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ vim README.md # (1)!
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git diff
diff --cc README.md
index 5377894,376d064..0000000
--- a/README.md
+++ b/README.md
@@@ -1,3 -1,1 +1,2 @@@
  # Git revert i cherrypick
- - Canvi A
 +- Canvi B
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git add README.md
jpuigcerver@fp:~/git_cherrypick (main|REVERTING) $ git revert --continue --no-edit
[main 6a5c752] Revert "Canvi A"
 1 file changed, 1 deletion(-)
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* 6a5c752 - (0 seconds ago) Revert "Canvi A" - Joan Puigcerver (HEAD -> main)
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
  1. S'ha editat manualment el fitxer per eliminar els marcadors de conflicte i la línia - Canvi A.

Cherry-pick

La comanda cherry-pick permet aplicar els canvis d'un commit concret sobre la branca actual.

Documentació

Documentació oficial de git cherry-pick

La sintaxi és la següent:

git cherry-pick <ref>

  • <ref>: Referència del commit que es vol aplicar.

Funcionament de git cherry-pick

Figura 2. Funcionament de git cherry-pick.

Exemple: git cherry-pick

En aquest cas, tornem a aplicar el Canvi C després de Canvi B amb git cherry-pick.

jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* 6a5c752 - (0 seconds ago) Revert "Canvi A" - Joan Puigcerver (HEAD -> main)
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ cat README.md
# Git revert i cherrypick
- Canvi B
jpuigcerver@fp:~/git_cherrypick (main) $ git cherry-pick 75f51e1
Auto-merging README.md
[main 0c28064] Canvi C
 Date: Sun Oct 20 22:15:45 2024 +0200
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* 0c28064 - (1 second ago) Canvi C - Joan Puigcerver (HEAD -> main)
* 6a5c752 - (0 seconds ago) Revert "Canvi A" - Joan Puigcerver
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ cat README.md
# Git revert i cherrypick
- Canvi B
- Canvi C

Resolució de conflictes

Aquesta acció pot generar conflictes si els canvis que es volen aplicar es produeixen en llocs que han segut modificats.

En aquest cas, passarem a l'estat CHERRY-PICKING i caldrà resoldre els conflictes manualment, de la mateixa manera que es fa en una fusió de branques (merge).

Exemple: Resolució de conflictes en git cherry-pick

En aquest cas, git cherry-pick ha generat un conflicte ja que Canvi A modificava la mateixa línia que Canvi B.

jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* 0c28064 - (1 second ago) Canvi C - Joan Puigcerver (HEAD -> main)
* 6a5c752 - (0 seconds ago) Revert "Canvi A" - Joan Puigcerver
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
jpuigcerver@fp:~/git_cherrypick (main) $ git cherry-pick 4d18d71
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply 4d18d71... Canvi A
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config advice.mergeConflict false"
jpuigcerver@fp:~/git_cherrypick (main|CHERRY-PICKING) $ vim README.md # (1)!
jpuigcerver@fp:~/git_cherrypick (main|CHERRY-PICKING) $ git diff
diff --cc README.md
index d6c55ca,2754255..0000000
--- a/README.md
+++ b/README.md
@@@ -1,3 -1,2 +1,4 @@@
  # Git revert i cherrypick
+ - Canvi A
 +- Canvi B
 +- Canvi C
jpuigcerver@fp:~/git_cherrypick (main|CHERRY-PICKING) $ git add README.md
jpuigcerver@fp:~/git_cherrypick (main|CHERRY-PICKING) $ git revert --continue --no-edit
[main d0bf36e] Canvi A
 Date: Sun Oct 20 22:15:45 2024 +0200
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_cherrypick (main) $ git lga
* d0bf36e - (1 second ago) Canvi A - Joan Puigcerver (HEAD -> main)
* 0c28064 - (1 second ago) Canvi C - Joan Puigcerver
* 6a5c752 - (0 seconds ago) Revert "Canvi A" - Joan Puigcerver
* aa99382 - (0 seconds ago) Revert "Canvi C i D" - Joan Puigcerver
* 2f610b9 - (1 second ago) Revert "Canvi E" - Joan Puigcerver
* ff4ae1c - (1 second ago) Canvi E - Joan Puigcerver
* a079d5b - (1 second ago) Canvi D - Joan Puigcerver
* 75f51e1 - (1 second ago) Canvi C - Joan Puigcerver
* fad1ea7 - (1 second ago) Canvi B - Joan Puigcerver
* 4d18d71 - (1 second ago) Canvi A - Joan Puigcerver
* 810ec42 - (1 second ago) Commit inicial - Joan Puigcerver
  1. S'ha editat manualment el fitxer per eliminar els marcadors de conflicte i posar Canvi A abans de Canvi B.

Comentaris