1193 votes

Comment fusionner un commit spécifique dans Git

J'ai forké une branche à partir d'un dépôt sur GitHub et commis quelque chose de spécifique pour moi. Maintenant, j'ai découvert que le dépôt original avait une fonctionnalité intéressante qui se trouvait à HEAD.

Je veux la fusionner uniquement sans les commits précédents. Que dois-je faire? Je sais comment fusionner tous les commits :

git branch -b une-bonne-fonctionnalite
git pull dépôt master
git checkout master
git merge une-bonne-fonctionnalite
git commit -a
git push

0 votes

Si vous essayez de faire cela par rapport à GitHub, cet article vous guidera à travers cela. markosullivan.ca/how-to-handle-a-pull-request-from-github

1305voto

VonC Points 414372

git cherry-pick devrait être votre réponse ici.

Appliquez le changement introduit par un commit existant.

N'oubliez pas de lire la réponse de bdonlan sur les conséquences du cherry-picking dans ce post :
"Tirer tous les commits d'une branche, pousser des commits spécifiques vers une autre", où :

A-----B------C
 \
  \
   D

devient :

A-----B------C
 \
  \
   D-----C'

Le problème avec ce commit est que git considère les commits comme incluant tout l'historique qui les précède.

Où C' a un ID SHA-1 différent.
De même, effectuer un cherry-pick d'un commit d'une branche à une autre implique essentiellement de générer un patch, puis de l'appliquer, perdant ainsi de l'historique de cette manière également.

Ce changement d'IDs de commit casse la fonctionnalité de fusion de git entre autres choses (bien que s'il est utilisé avec parcimonie, il existe des heuristiques qui masqueront cela).
Plus important encore, cela ignore les dépendances fonctionnelles - si C utilisait en réalité une fonction définie dans B, vous ne le saurez jamais.

1 votes

@openid000 : "des branches plus fines" : ce qui correspond exactement à ce que bdonlan a suggéré dans sa réponse.

9 votes

Note: "git rebase" change également SHA-1. Voir aussi "git rebase vs. git merge (stackoverflow.com/questions/804115/git-rebase-vs-git-merge) et "git workflow" (stackoverflow.com/questions/457927/…) pour les cas où "git rebase" est légitime.

1 votes

Entre les "branches fines", le "cherry-pick" et le "rebase", vous aurez alors toutes les possibilités pour gérer le code dans les branches avec git.

845voto

bdonlan Points 90068

Vous pouvez utiliser git cherry-pick pour appliquer un seul commit à votre branche actuelle.

Exemple: git cherry-pick d42c389f

73 votes

+1 pour votre ancien post sur le cherry picking ( stackoverflow.com/questions/880957/… ). J'ai pris la liberté de copier un extrait dans ma propre réponse ci-dessus.

5 votes

Probablement git cherry-pick d42c ou git cherry-pick d42c3 fonctionnera. Git est futé. ;)

3 votes

Fatal: mauvaise révision

55voto

ShitalShah Points 2213

Disons que vous voulez fusionner le commit e27af03 de la branche X à la branche principale.

git checkout master
git cherry-pick e27af03
git push

44voto

Brain2000 Points 865

J'avais l'habitude de faire du cherry-picking, mais j'ai découvert que j'avais parfois des problèmes mystérieux de temps en temps. J'ai trouvé un blog de Raymond Chen, un vétéran de 25 ans chez Microsoft, qui décrit certains scénarios où le cherry-picking peut poser des problèmes dans certains cas.

Une des règles de base est que si vous faites du cherry-picking d'une branche à une autre, puis fusionnez ultérieurement entre ces branches, il est probable que vous rencontriez des problèmes plus tôt ou plus tard.

Voici une référence aux blogs de Raymond Chen sur ce sujet: https://devblogs.microsoft.com/oldnewthing/20180312-00/?p=98215

Le seul problème que j'ai rencontré avec le blog de Raymond est qu'il n'a pas fourni d'exemple complet. Je vais donc essayer d'en fournir un ici.

La question ci-dessus demande comment fusionner uniquement le commit pointé par HEAD dans la branche a-good-feature avec master.

Voici comment cela se ferait:

  1. Trouvez l'ancêtre commun entre les branches master et a-good-feature.
  2. Créez une nouvelle branche à partir de cet ancêtre, nous l'appellerons nouvelle branche patch.
  3. Faites du cherry-pick d'un ou plusieurs commits dans cette nouvelle branche patch.
  4. Fusionnez la branche patch dans les deux branches master et a-good-feature.
  5. La branche master contiendra désormais les commits, et les branches master et a-good-feature auront également un nouvel ancêtre commun, ce qui résoudra tout problème futur si d'autres fusions sont effectuées ultérieurement.

Voici un exemple de ces commandes:

git checkout master...a-good-feature  [checkout de l'ancêtre commun]
git checkout -b patch
git cherry-pick a-good-feature  [ce n'est pas seulement le nom de la branche, mais aussi le commit que nous voulons]
git checkout master
git merge patch
git checkout a-good-feature
git merge -s ours patch

Il est peut-être bon de noter que la dernière ligne qui a été fusionnée dans la branche a-good-feature a utilisé la stratégie de fusion "-s ours". La raison en est que nous devons simplement créer un commit dans la branche a-good-feature qui pointe vers un nouvel ancêtre commun, et puisque le code est déjà dans cette branche, nous voulons nous assurer qu'il n'y a aucune chance de conflit de fusion. Cela devient plus important si le(s) commit(s) que vous fusionnez ne sont pas les plus récents.

Les scénarios et les détails entourant les fusions partielles peuvent devenir assez complexes, je vous recommande donc de lire les 10 parties du blog de Raymond Chen pour avoir une compréhension complète de ce qui peut mal tourner, comment l'éviter, et pourquoi cela fonctionne.

36voto

user3799762 Points 347

Essayons de prendre un exemple et de comprendre :

J'ai une branche, disons master, pointant vers X , et j'ai une nouvelle branche pointant vers Y .

Y \= commits de la branche - quelques commits

Disons maintenant que pour la branche Y je dois combler l'écart entre la branche master et la nouvelle branche. Voici la procédure que nous pouvons suivre :

Étape 1 :

git checkout -b local origin/new

où local est le nom de la branche. Un nom quelconque peut être donné.

Étape 2 :

  git merge origin/master --no-ff --stat -v --log=300

Fusionnez les commits de la branche master avec la nouvelle branche et créez également un commit de fusion avec un message de journal avec des descriptions d'une ligne au maximum de commits réels qui sont fusionnés.

Pour plus d'informations et de paramètres sur la fusion Git, veuillez consulter :

git merge --help

De plus, si vous devez fusionner un commit spécifique, vous pouvez utiliser :

git cherry-pick

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X