1441 votes

Comment sélectionner plusieurs validations cherry-pick

J'ai deux branches. Le commit a est la tête de l'une, tandis que l'autre a les commits b, c, d, e et f au-dessus de a. Je veux déplacer c, d, e et f vers la première branche sans le commit b. En utilisant cherry-pick, c'est facile : passez à la première branche, cherry-pick un par un les commits de c à f et rebasez la deuxième branche sur la première. Mais y a-t-il un moyen de cherry-pick tous les commits de c à f en une seule commande?

Voici une description visuelle du scénario (merci JJD) :

Un commit montrant un état 'avant' et 'après'. Dans l'état 'avant', les commits de a à f sont connectés dans une séquence continue. Dans l'état 'après', les commits de c à f ont été déplacés pour se connecter directement à a sans réorganisation, laissant le commit b derrière.

16 votes

Le rebase que vous mentionnez n'est pas vraiment pertinent pour la question, n'est-ce pas? (Je comprends que vous vouliez que b soit basé sur f plus tard, mais cela n'a rien à voir avec le cherry-picking.)

2201voto

Eric Darchis Points 2789

Git 1.7.2 a introduit la possibilité de cherry-pick une plage de commits. Du notes de version:

git cherry-pick a appris à choisir une plage de commits (par exemple cherry-pick A..B et cherry-pick --stdin), tout comme git revert; ceux-ci ne prennent pas en charge le contrôle de séquençage plus agréable que rebase [-i] propose, cependant.

Pour cherry-pick tous les commits du commit A au commit B (où A est plus ancien que B), exécutez:

git cherry-pick A^..B

Si vous voulez ignorer A lui-même, exécutez:

git cherry-pick A..B

Notes des commentaires:

  • A doit être plus ancien que B, ou A doit être d'une autre branche.
  • Sous Windows, cela devrait être A^^..B car le chapeau doit être échappé, ou cela devrait être "A^..B" (guillemets doubles).
  • Dans le shell zsh, cela devrait être 'A^..B' (guillemets simples) car le chapeau est un caractère spécial.
  • Pour une exposition, voir la réponse de Gabriel Staples.

(Crédits à damian, J. B. Rainsberger, sschaef, Neptilo, Pete et TMin dans les commentaires.)

307 votes

Dans le formulaire "cherry-pick A..B", A doit être plus ancien que B. Si ils sont dans le mauvais ordre, la commande échouera silencieusement.

21 votes

Si vous avez git 1.7.1 ou une version antérieure et que vous ne pouvez pas mettre à jour, vous pouvez assez rapidement les récolter un par un en exécutant git cherry-pick f~3 puis git cherry-pick f~2, etc. jusqu'à git cherry-pick f (en appuyant sur la flèche vers le haut pour obtenir la commande précédente afin de changer rapidement le numéro et de l'exécuter, cela devrait être similaire dans la plupart des consoles).

34 votes

Il peut être bon de savoir que cette syntaxe fonctionne également avec les noms de branches. git cherry-pick master..somebranch sélectionnera tous les commits sur somebranch depuis master (en supposant qu'ils aient déjà été rebasés sur master) et les appliquera à votre branche actuelle.

140voto

Charles Bailey Points 244082

La manière la plus simple de le faire est avec l'option onto de rebase. Supposons que la branche qui se termine actuellement à a s'appelle mybranch et c'est la branche sur laquelle vous voulez déplacer c-f.

# checkout mybranch
git checkout mybranch

# reset it to f (currently includes a)
git reset --hard f

# rebase every commit after b and transplant it onto a
git rebase --onto a b

1 votes

Merci! Pour une réponse complète, pourriez-vous ajouter git checkout secondbranch && git rebase mybranch

2 votes

Cette réponse m'a beaucoup aidé à comprendre quel commit correspond à quoi dans ce scénario. De plus: vous pouvez également utiliser le mode interactif de rebase. Merci, @Charles!

6 votes

La beauté de cette approche est que vous pouvez utiliser --interactive pour supprimer certains commits de la séquence ou les réorganiser avant le "cherry pick". +1

99voto

wolfc Points 653

Ou la commande demandée en une seule ligne:

git rebase --onto a b f

7 votes

Si seulement pour sa brièveté, c'est la meilleure réponse.

12 votes

A voté mais vous laissera dans l'état HEAD détaché si f est un commit (par opposition à une branche) - vous devriez éditer pour ajouter que l'on devrait vérifier une branche comme dans réponse ci-dessous

0 votes

Pourquoi se soucier du reste?

80voto

JJD Points 7539

Vous pouvez utiliser une combinaison sérielle de git rebase et git branch pour appliquer un groupe de commits sur une autre branche. Comme déjà posté par wolfc, la première commande copie en fait les commits. Cependant, le changement n'est pas visible tant que vous n'ajoutez pas un nom de branche au commit le plus récent du groupe.

Veuillez ouvrir l'image dans un nouvel onglet...

Workflow

Pour résumer les commandes en forme de texte :

  1. Ouvrez gitk en tant que processus indépendant en utilisant la commande : gitk --all &.
  2. Exécutez git rebase --onto a b f.
  3. Appuyez sur F5 dans gitk. Rien ne change. Mais aucun HEAD n'est marqué.
  4. Exécutez git branch selection
  5. Appuyez sur F5 dans gitk. La nouvelle branche avec ses commits apparaît.

Cela devrait clarifier les choses :

  • Le commit a est la nouvelle destination racine du groupe.
  • Le commit b est le commit avant le premier commit du groupe (exclus).
  • Le commit f est le dernier commit du groupe (inclus).

Ensuite, vous pourriez utiliser git checkout feature && git reset --hard b pour supprimer les commits c à f de la branche feature.

En plus de cette réponse, j'ai écrit un article de blog qui décrit les commandes dans un autre scénario qui devrait aider à les utiliser de manière générale.

2 votes

Si la ma branche (les commits a..f) n'est plus nécessaire, cela peut être simplifié en : git rebase --ont a b ma_branche au fait, quel programme utilise ces nifty images git ?

2 votes

@M.et_Mme_D Merci pour votre commentaire. Je pense avoir utilisé cacoo.com pour dessiner les images.

28voto

Dustin Points 35205
git rev-list --reverse b..f | xargs -n 1 git cherry-pick

git rev-list imprime toutes les révisions de la branche b à la branche f (en inversé) de sorte que lorsque chaque ligne (le hachage du commit) est passée dans l'ordre, elle sera cherrypickée sur le git HEAD actuel. c'est-à-dire git cherry-pick {hachage de c}; git cherry-pick {hachage de d}; ...

-- @coderatchet commentaire

2 votes

Fonctionne parfaitement s'il n'y a pas de conflits, sinon "rebase sur" pourrait être plus facile car vous n'aurez pas à comprendre où il s'est arrêté et à réappliquer le reste des correctifs.

12 votes

Veuillez ajouter des commentaires expliquant ce que cela fait

9 votes

Comme personne ne l'a expliqué... git rev-list imprime toutes les révisions de la branche b à f (inversées) de sorte que lorsque chaque ligne (le hachage de validation) est passée dans l'ordre, chacune sera cherry-pické sur l'état actuel de git HEAD. c'est-à-dire git cherry-pick {hachage de c}; git cherry-pick {hachage de d}; ...

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