Comment annuler une opération git cherry-pick

GitBeginner
Pratiquer maintenant

Introduction

La fonctionnalité cherry-pick de Git vous permet d'appliquer des commits spécifiques d'une branche à une autre. Bien que puissante, il peut arriver que vous ayez besoin d'inverser une opération de cherry-pick en raison d'erreurs ou de conflits. Dans ce lab, vous apprendrez comment effectuer un cherry-pick et ensuite utiliser diverses méthodes pour l'annuler si nécessaire. À la fin, vous aurez une expérience pratique des opérations de cherry-pick et les compétences nécessaires pour récupérer des problèmes courants.

Configuration d'un dépôt de test

Dans cette étape, nous allons créer un dépôt Git de test pour pratiquer les opérations de cherry-pick. Cela fournira un environnement sûr pour expérimenter avec diverses commandes Git.

Création d'un nouveau dépôt Git

Commençons par créer un nouveau répertoire pour notre dépôt de test et l'initialiser en tant que dépôt Git :

mkdir -p ~/project/cherry-pick-lab
cd ~/project/cherry-pick-lab
git init

Vous devriez voir une sortie similaire à :

Initialized empty Git repository in /home/labex/project/cherry-pick-lab/.git/

Configuration de l'utilisateur Git

Avant de pouvoir faire des commits, nous devons configurer un nom d'utilisateur et une adresse e-mail pour Git :

git config --local user.name "LabEx User"
git config --local user.email "labex@example.com"

Création des commits initiaux sur la branche principale

Créons quelques commits initiaux sur la branche principale :

## Create and commit the first file
echo "## Cherry Pick Lab" > README.md
git add README.md
git commit -m "Initial commit with README"

## Create and commit a second file
echo "console.log('Hello, world!');" > app.js
git add app.js
git commit -m "Add main application file"

Visualisation de l'historique des commits

Vérifions notre historique des commits pour nous assurer que tout est correctement configuré :

git log --oneline

Vous devriez voir une sortie similaire à :

abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README

Les hachages de commit réels seront différents sur votre système. Notez le hachage de commit pour "Add main application file" car nous l'utiliserons plus tard.

Création d'une branche de fonctionnalité

Maintenant, créons une branche de fonctionnalité où nous apporterons des modifications supplémentaires :

git checkout -b feature-branch

Vous devriez voir une sortie similaire à :

Switched to a new branch 'feature-branch'

Ajoutons maintenant quelques commits à cette branche de fonctionnalité :

## Create and commit a new feature file
echo "function newFeature() { return 'awesome'; }" > feature.js
git add feature.js
git commit -m "Add new feature function"

## Modify the README file
echo -e "## Cherry Pick Lab\n\nThis repo demonstrates git cherry-pick operations." > README.md
git add README.md
git commit -m "Update README with project description"

Nous avons maintenant une branche principale avec deux commits et une branche de fonctionnalité avec deux commits supplémentaires. Dans l'étape suivante, nous utiliserons cherry-pick pour appliquer l'un des commits de la branche de fonctionnalité à la branche principale.

Effectuer une opération de Cherry-pick

Dans cette étape, nous allons apprendre à utiliser la commande cherry-pick pour appliquer un commit spécifique d'une branche à une autre. Ceci est utile lorsque vous souhaitez incorporer sélectivement des modifications d'une branche à une autre.

Comprendre le Cherry-pick

Le cherry-picking dans Git vous permet de choisir un commit spécifique d'une branche et de l'appliquer à une autre branche. Contrairement au merge ou au rebase qui appliquent généralement plusieurs commits, le cherry-picking applique un seul commit à la fois.

Revenir à la branche principale

Tout d'abord, revenons à la branche principale où nous voulons appliquer un commit de la branche de fonctionnalité :

git checkout main

Vous devriez voir une sortie confirmant le changement :

Switched to branch 'main'

Visualisation des commits de la branche de fonctionnalité

Avant de faire le cherry-pick, examinons les commits de la branche de fonctionnalité que nous pourrions vouloir appliquer à la branche principale :

git log feature-branch --oneline

Cela affichera tous les commits de la branche de fonctionnalité, y compris ceux partagés avec la branche principale. Vous verrez une sortie similaire à :

1234abc Update README with project description
5678def Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Notez le hachage de commit pour "Add new feature function" (dans cet exemple, c'est 5678def). Nous utiliserons ce hachage à l'étape suivante.

Cherry-picking d'un commit

Maintenant, faisons le cherry-pick du commit "Add new feature function" de la branche de fonctionnalité dans notre branche principale :

git cherry-pick [COMMIT_HASH]

Remplacez [COMMIT_HASH] par le hachage réel que vous avez noté précédemment. Par exemple :

git cherry-pick 5678def

Si le cherry-pick réussit, vous verrez une sortie similaire à :

[main 98765ab] Add new feature function
 1 file changed, 1 insertion(+)
 create mode 100644 feature.js

Vérification du Cherry-pick

Vérifions que le cherry-pick a fonctionné comme prévu :

git log --oneline

Vous devriez maintenant voir le commit cherry-picked dans l'historique de votre branche principale :

98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Vous pouvez également vérifier que le fichier existe :

ls -la

Vous devriez voir feature.js listé dans la sortie :

total 16
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex   29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex   42 Jan 1 00:00 feature.js
-rw-r--r-- 1 labex labex   16 Jan 1 00:00 README.md

L'opération de cherry-pick a appliqué avec succès le commit de la branche de fonctionnalité à la branche principale. Dans l'étape suivante, nous apprendrons comment annuler ce cherry-pick si nécessaire.

Annuler un Cherry-pick avec Git Reset

Maintenant que nous avons réussi à faire un cherry-pick d'un commit, apprenons à annuler cette opération. Dans cette étape, nous utiliserons la commande git reset, qui est la méthode la plus simple pour annuler un cherry-pick récent.

Comprendre Git Reset

La commande git reset déplace le pointeur de la branche actuelle vers un commit spécifié, "annulant" ainsi efficacement tous les commits qui sont venus après ce point. Il existe trois principaux modes de git reset :

  • --soft : Déplace le pointeur de la branche mais laisse les modifications préparées (staged)
  • --mixed (par défaut) : Déplace le pointeur de la branche et désarchive les modifications (unstages)
  • --hard : Déplace le pointeur de la branche et rejette toutes les modifications

Pour annuler un cherry-pick, nous utiliserons l'option --hard pour supprimer complètement le commit cherry-picked et ses modifications.

Vérification de l'état actuel

Tout d'abord, vérifions notre état actuel pour confirmer que nous sommes sur la branche principale avec le commit cherry-picked :

git log --oneline -n 3

Vous devriez voir une sortie similaire à :

98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Annulation du Cherry-pick avec Git Reset

Pour annuler l'opération de cherry-pick, nous utiliserons git reset avec l'option --hard pour déplacer le pointeur de la branche d'un commit en arrière :

git reset --hard HEAD~1

Cette commande indique à Git de réinitialiser la branche au commit précédant le HEAD actuel (la partie ~1 signifie "un commit avant").

Vous devriez voir une sortie similaire à :

HEAD is now at abcd123 Add main application file

Vérification de la réinitialisation

Vérifions que le cherry-pick a été annulé :

git log --oneline

Vous devriez voir que le commit cherry-picked n'est plus dans l'historique :

abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README

Vérifions également si le fichier feature.js a été supprimé :

ls -la

La sortie ne devrait pas inclure feature.js :

total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex   29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex   16 Jan 1 00:00 README.md

Félicitations ! Vous avez réussi à annuler une opération de cherry-pick en utilisant git reset. Cette méthode est propre et simple, mais elle réécrit l'historique, elle ne doit donc être utilisée que pour les modifications locales qui n'ont pas été poussées vers un dépôt partagé.

Annuler un Cherry-pick avec Git Revert

Dans l'étape précédente, nous avons utilisé git reset pour annuler un cherry-pick. Cependant, git reset réécrit l'historique, ce qui peut être problématique si vous avez déjà poussé vos modifications vers un dépôt partagé. Dans cette étape, nous allons apprendre à utiliser git revert pour annuler en toute sécurité un cherry-pick sans réécrire l'historique.

Comprendre Git Revert

La commande git revert crée un nouveau commit qui annule les modifications introduites par un commit précédent. Contrairement à git reset, qui supprime les commits de l'historique, git revert ajoute un nouveau commit qui contrecarre les modifications, préservant ainsi l'historique des commits.

Effectuer à nouveau un Cherry-pick

Tout d'abord, faisons à nouveau le cherry-pick du commit afin d'avoir quelque chose à annuler :

## Get the commit hash from the feature branch
FEATURE_HASH=$(git log feature-branch --oneline | grep "new feature" | cut -d ' ' -f 1)

## Cherry-pick the commit
git cherry-pick $FEATURE_HASH

Vous devriez voir une sortie similaire à :

[main 98765ab] Add new feature function
 1 file changed, 1 insertion(+)
 create mode 100644 feature.js

Vérification de l'état actuel

Confirmons que le cherry-pick a réussi :

git log --oneline -n 3
ls -la

Vous devriez voir le commit cherry-picked dans l'historique et le fichier feature.js dans la liste des répertoires.

Annulation du Cherry-pick

Maintenant, utilisons git revert pour annuler le cherry-pick tout en préservant l'historique :

git revert HEAD --no-edit

L'indicateur --no-edit indique à Git d'utiliser le message de commit par défaut sans ouvrir d'éditeur.

Vous devriez voir une sortie similaire à :

[main abc9876] Revert "Add new feature function"
 1 file changed, 1 deletion(-)
 delete mode 100644 feature.js

Vérification de l'annulation

Vérifions l'historique des commits :

git log --oneline -n 4

Vous devriez voir à la fois le commit cherry-picked et le commit d'annulation :

abc9876 (HEAD -> main) Revert "Add new feature function"
98765ab Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Maintenant, vérifions si le fichier feature.js a été supprimé :

ls -la

La sortie ne devrait pas inclure feature.js :

total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex   29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex   16 Jan 1 00:00 README.md

Bien que git reset et git revert atteignent le même résultat final (suppression des modifications introduites par le cherry-pick), ils le font de différentes manières :

  • git reset supprime le commit de l'historique, ce qui peut causer des problèmes si le commit a été partagé avec d'autres.
  • git revert ajoute un nouveau commit qui annule les modifications, préservant l'historique des commits, ce qui est plus sûr pour les dépôts partagés.

Le choix entre ces méthodes dépend de votre situation spécifique :

  • Utilisez git reset pour les modifications locales qui n'ont pas été partagées
  • Utilisez git revert pour les modifications qui ont été poussées vers un dépôt partagé

Gérer les conflits de Cherry-pick

Parfois, lorsque vous faites un cherry-pick d'un commit, Git peut rencontrer des conflits si les modifications du commit entrent en conflit avec les modifications de votre branche actuelle. Dans cette étape, nous allons apprendre à gérer les conflits de cherry-pick et à annuler une opération de cherry-pick.

Création d'un scénario avec des conflits potentiels

Tout d'abord, créons un scénario qui entraînera un conflit de cherry-pick :

## Switch to main branch and modify README.md
git checkout main
echo -e "## Cherry Pick Lab\n\nThis is the main branch README." > README.md
git commit -am "Update README in main branch"

## Switch to feature branch and make a conflicting change to README.md
git checkout feature-branch
echo -e "## Cherry Pick Lab\n\nThis README has been updated in the feature branch." > README.md
git commit -am "Update README in feature branch"

Tentative de Cherry-pick avec des conflits

Maintenant, revenons à la branche principale et essayons de faire un cherry-pick du commit de la branche feature :

git checkout main
CONFLICT_HASH=$(git log feature-branch --oneline | grep "Update README in feature" | cut -d ' ' -f 1)
git cherry-pick $CONFLICT_HASH

Étant donné que les deux branches ont modifié les mêmes lignes dans README.md, vous devriez voir un conflit :

error: could not apply a1b2c3d... Update README in feature branch
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

Visualisation du conflit

Examinons le conflit :

git status

Vous devriez voir une sortie indiquant un conflit dans README.md :

On branch main
You are currently cherry-picking commit a1b2c3d.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

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

no changes added to commit (use "git add" and/or "git commit -a")

Regardons le contenu du fichier en conflit :

cat README.md

Vous devriez voir quelque chose comme :

## Cherry Pick Lab

<<<<<<< HEAD
This is the main branch README.
=======
This README has been updated in the feature branch.
>>>>>>> a1b2c3d... Update README in feature branch

Résolution du conflit

Pour résoudre le conflit, nous devons modifier le fichier et décider quelles modifications conserver. Modifions README.md pour inclure les deux modifications :

echo -e "## Cherry Pick Lab\n\nThis is the main branch README.\n\nThis README has also been updated with content from the feature branch." > README.md

Maintenant, marquons le conflit comme résolu et continuons le cherry-pick :

git add README.md
git cherry-pick --continue

Git ouvrira un éditeur avec un message de commit par défaut. Enregistrez et fermez l'éditeur pour terminer le cherry-pick.

Annulation d'un Cherry-pick

Parfois, vous pouvez décider de ne pas vouloir résoudre les conflits et préféreriez annuler l'opération de cherry-pick. Créons un autre conflit, puis annulons le cherry-pick :

## Create another conflicting commit in feature branch
git checkout feature-branch
echo "// This will conflict with app.js in main" > app.js
git commit -am "Modify app.js in feature branch"

## Try to cherry-pick this commit to main
git checkout main
ANOTHER_CONFLICT=$(git log feature-branch --oneline | grep "Modify app.js" | cut -d ' ' -f 1)
git cherry-pick $ANOTHER_CONFLICT

Vous devriez voir un autre conflit. Cette fois, annulons le cherry-pick :

git cherry-pick --abort

Vous devriez voir que l'opération de cherry-pick a été annulée et que votre répertoire de travail a été restauré à son état précédent :

git status

Output:

On branch main
nothing to commit, working tree clean

La gestion des conflits lors des opérations de cherry-pick est une compétence essentielle pour les utilisateurs de Git. Vous avez trois options lorsque vous rencontrez un conflit :

  1. Résoudre le conflit manuellement, puis utiliser git add et git cherry-pick --continue
  2. Ignorer le commit en conflit avec git cherry-pick --skip
  3. Annuler l'ensemble de l'opération de cherry-pick avec git cherry-pick --abort

La meilleure approche dépend de la situation spécifique et des exigences de votre projet.

Résumé

Dans ce lab, vous avez acquis une expérience pratique avec la fonctionnalité cherry-pick de Git et appris plusieurs façons d'annuler les opérations de cherry-pick :

  1. Vous avez créé un dépôt de test avec plusieurs branches et commits pour vous entraîner.
  2. Vous avez effectué une opération de cherry-pick pour appliquer un commit spécifique d'une branche à une autre.
  3. Vous avez appris à annuler un cherry-pick en utilisant git reset, ce qui convient aux modifications locales.
  4. Vous avez exploré comment annuler en toute sécurité un cherry-pick en utilisant git revert, qui préserve l'historique.
  5. Vous vous êtes entraîné à gérer les conflits de cherry-pick et avez appris à annuler une opération de cherry-pick.

Ces compétences sont inestimables lorsque vous travaillez avec Git dans des projets réels. Le cherry-picking vous permet d'appliquer sélectivement des modifications entre les branches, tandis que savoir comment annuler les cherry-picks vous aide à récupérer des erreurs et à maintenir un historique Git propre.

Rappelez-vous que les différentes méthodes d'annulation servent des objectifs différents :

  • Utilisez git reset pour les modifications locales qui n'ont pas été partagées.
  • Utilisez git revert pour les modifications qui ont été poussées vers un dépôt partagé.
  • Utilisez git cherry-pick --abort pour annuler une opération de cherry-pick en cours.

En comprenant ces options, vous pouvez choisir la méthode la plus appropriée pour votre situation spécifique.