729 votes

git cherry-pick dit "...38c74d est une fusion mais aucune option -m n'a été donnée"

J'ai fait quelques changements dans ma branche master et je veux les apporter en amont. Lorsque je sélectionne les commits suivants. Cependant, je suis bloqué sur fd9f578 où git dit :

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

Qu'est-ce que git essaie de me dire et est-ce que cherry-pick est la bonne chose à utiliser ici ? La branche master inclut des changements de fichiers qui ont été modifiés dans la branche amont, donc je suis sûr qu'il y aura quelques conflits de fusion mais ils ne sont pas trop difficiles à résoudre. Je sais quels changements sont nécessaires à quel endroit.

Ce sont les commits que je veux apporter en amont.

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...

0 votes

Si tout ce que vous voulez, c'est faire passer un ensemble de modifications d'une branche à une autre, sans vous soucier de l'historique des fusions, allez directement à cette réponse en or .

792voto

Borealid Points 35075

La façon dont un cherry-pick fonctionne est de prendre la différence qu'un changeset représente (la différence entre l'arbre de travail à ce point et l'arbre de travail de son parent), et de l'appliquer à votre branche actuelle.

Donc, si un commit a deux parents ou plus, il représente aussi deux différences ou plus - laquelle doit être appliquée ?

Vous essayez de faire une sélection fd9f578 qui était une fusion avec deux parents. Vous devez donc indiquer à la commande cherry-pick par rapport à laquelle la différence doit être calculée, en utilisant la commande -m option. Par exemple, git cherry-pick -m 1 fd9f578 d'utiliser le parent 1 comme base.

Je ne peux pas dire avec certitude pour votre situation particulière, mais en utilisant git merge au lieu de git cherry-pick est généralement conseillé. Lorsque vous choisissez un commit de fusion, il s'effondre. tous les changements effectués dans le parent que vous n'avez pas spécifié pour -m dans ce un engagement . Vous perdez toute leur histoire, et rassemblez toutes leurs différences. A vous de voir.

4 votes

@wufoo Tu devrais probablement aussi apprendre à connaître git rebase - c'est comme une fusion, mais au lieu d'intégrer deux branches, on en transplante une pour qu'elle s'assoit sur l'autre.

163 votes

Comment connaissez-vous le numéro du parent ?

82 votes

@Anentropic 1 est le "premier parent", 2 est le "second parent", et ainsi de suite. L'ordre est celui dans lequel ils sont listés dans le commit (tel que vu par git show et autres).

144voto

gavincook Points 1224

-m signifie le numéro du parent.

De la doc git :

Habituellement, vous ne pouvez pas "cherry-picker" une fusion parce que vous ne savez pas quel côté de la fusion doit être considéré comme la ligne principale. Cette option spécifie le numéro de parent (à partir de 1) de la ligne principale et permet à cherry-pick de rejouer la modification par rapport au parent spécifié.

Par exemple, si votre arbre de commit est comme ci-dessous :

- A - D - E - F -   master
   \     /
    B - C           branch one

puis git cherry-pick E produira le problème que vous avez rencontré.

git cherry-pick E -m 1 signifie utiliser D-E alors que git cherry-pick E -m 2 signifie utiliser B-C-E .

76voto

Kay V Points 749

Simplifier. Cherry-picker les commits. Ne pas choisir la fusion.

Si vous déterminez que vous devez inclure la fusion plutôt que d'extraire les commits liés, vous avez deux options :

  1. (Plus compliqué et plus obscur ; élimine également l'historique) vous pouvez indiquer quel parent doit faire la demande.
  • Utilisez le -m pour le faire. Par exemple, git cherry-pick -m 1 fd9f578 utilisera le premier parent listé dans la fusion comme base.

  • Considérez également que lorsque vous choisissez un commit de fusion, il s'effondre. tous les changements effectués dans le parent que vous n'avez pas spécifié pour -m dans ce un engagement . Vous perdez toute leur histoire, et rassemblez toutes leurs différences. A vous de voir.

  1. (plus simple et plus familier ; préserve l'historique) vous pouvez utiliser git merge au lieu de git cherry-pick .
  • Comme d'habitude avec git merge il essaiera d'appliquer tous les commits qui existent sur la branche que vous fusionnez, et les listera individuellement dans votre journal git.

44voto

Daira Hopwood Points 687

La réponse de @Borealid est correcte, mais supposons que vous ne vous souciez pas de préserver l'historique de fusion exact d'une branche et que vous voulez juste en sélectionner une version linéarisée. Voici un moyen simple et sûr de le faire :

État de départ : vous êtes sur la branche X et vous voulez sélectionner les commits. Y..Z .

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (facultatif) git branch -D tempZ

Ce que cela fait, c'est de créer une branche tempZ sur la base de Z mais avec l'histoire de Y linéarisé, et ensuite l'extraire sur une copie de X appelé newX . (Il est plus sûr de faire cela sur une nouvelle branche plutôt que de muter X .) Bien sûr, il peut y avoir des conflits à l'étape 4, que vous devrez résoudre de la manière habituelle ( cherry-pick fonctionne tout à fait comme rebase à cet égard). Enfin, il supprime le fichier temporaire tempZ branche.

Si l'étape 2 donne le message "La branche actuelle tempZ est à jour", alors Y..Z était déjà linéaire, alors ignorez ce message et passez aux étapes 3 et suivantes.

Puis revoir newX et voir si cela a fait ce que vous vouliez.

(Remarque : ce n'est pas la même chose qu'un simple git rebase X lorsqu'il s'agit d'une branche Z car elle ne dépend en aucune façon de la relation entre X y Y ; il peut y avoir des commits entre l'ancêtre commun et le Y que vous ne vouliez pas.)

5voto

ephemerr Points 756

La simplification de la méthode de @Daira Hopwood est bonne pour choisir un seul engagement. Ne nécessite pas de branches temporaires.

Dans le cas de l'auteur :

  • Z est recherché (fd9f578)
  • Y est engagé avant lui
  • X branche de travail actuelle

alors faites-le :

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit

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