Extraire tous les commits d'une branche, pousser les commits spécifiés vers une autre

102

J'ai les branches suivantes:

  • master
  • production

et les succursales distantes suivantes:

  • origin/master
  • origin/production

J'ai un script qui récupère la origin/masterbranche et récupère la différence de ce qui a changé depuis mon dernier fetch ( log -p master..origin/master). Puis je fusionne origin/master.

Les validations trouvées sont transmises à un outil de révision de code.

Je veux pousser les commits réussis - et seulement eux - vers la branche de production, puis bien sûr vers origin/production.

Comment puis-je le faire?

De plus, j'ai 2 scripts en cours d'exécution: celui qui récupère origin/master, envoie les détails de la validation dans une base de données et fusionne, et l'autre que j'écris actuellement qui devra pousser les validations réussies.

J'aimerais que ces 2 scripts fonctionnent tout en évitant les conditions de course / les conflits de fusion. Puisque je ne veux travailler qu'avec des commits spécifiés, il existe peut-être un moyen de me débarrasser des commits dont je ne veux pas?

Sylvain
la source
Qu'entendez-vous par «commits réussis»?
bdonlan
celui qui a été examiné et marqué comme réussi. cela n'a pas vraiment d'importance ici, l'important est qu'il y a des commits que je veux garder et pousser vers une autre branche, et d'autres dont je veux me débarrasser / ignorer.
Sylvain

Réponses:

313

Le terme que je pense que vous recherchez est un «choix cerise». Autrement dit, prenez un seul commit au milieu d'une branche et ajoutez-le à une autre:

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

devient

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

Ceci, bien sûr, peut être fait avec la commande git cherry-pick.

Le problème avec ce commit est que git considère que les commits incluent tout l'historique avant eux - donc, si vous avez trois commits comme ceci:

A-----B-----C

Et essayez de vous débarrasser de B, vous devez créer un tout nouveau commit comme ceci:

A-----------C'

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

Cette modification des ID de validation interrompt la fonctionnalité de fusion de git entre autres (bien que si elle est utilisée avec parcimonie, il existe des heuristiques qui couvriront cela). Plus important encore, il ignore les dépendances fonctionnelles - si C a réellement utilisé une fonction définie en B, vous ne le saurez jamais.

Peut-être qu'une meilleure façon de gérer cela serait d'avoir des branches plus fines. Autrement dit, au lieu d'avoir simplement un «maître», ayez «featureA», «bugfixB», etc. Examinez le code sur une branche entière à la fois - où chaque branche est très concentrée sur une seule chose - puis fusionnez-la une branche lorsque vous avez terminé. C'est le flux de travail pour lequel git est conçu et ce pour quoi il est bon :)

Si vous insistez pour traiter les choses au niveau des correctifs, vous voudrez peut-être regarder darcs - il considère un référentiel comme un ensemble de correctifs, et donc le cherry picking devient l'opération fondamentale. Cependant, cela a son propre ensemble de problèmes, comme être très lent :)

Edit: De plus, je ne suis pas sûr de comprendre votre deuxième question, sur les deux scripts. Peut-être pourriez-vous le décrire plus en détail, éventuellement comme une question distincte pour éviter que les choses ne deviennent confuses?

bdonlan
la source
À propos de ma deuxième question, je veux juste m'assurer que les processus de récupération des modifications (1er script) et de poussée des commits donnés vers un autre emplacement (2ème script) peuvent fonctionner sans condition de concurrence / conflit de fusion, tout en travaillant avec différentes branches. Mais au final je suppose que ça n'a pas d'importance puisque je pourrais fusionner les 2 scripts en un seul pour que les 2 scripts ne fonctionnent pas simultanément :)
Sylvain
9
"Cette modification des ID de validation interrompt la fonctionnalité de fusion de git entre autres" @bdonlan veuillez expliquer comment la fonctionnalité de fusion est freinée. Qu'est-ce que ça veut dire?
Narek
5
@Narek Il signifie probablement que les changements dans le commit C 'entreront en conflit avec les mêmes changements dans le commit C lorsque vous fusionnerez la deuxième branche. C'est la conséquence de la perte de l'historique derrière le commit C.
bytefu
1
«Et essayez de vous débarrasser de B» - pourquoi essayez-vous de vous débarrasser de B?
d512 le
3
@ user1334007, il veut dire qu'avant c'était ABC. Maintenant, en raison de votre choix cerise de C, votre branche est AD-C ', qui ne contient plus' B '.
AnneTheAgile
1

Je me rends compte que c'est une vieille question, mais elle est référencée ici: Comment fusionner un commit spécifique dans Git

Par conséquent, une réponse plus récente: utilisez des branches de fonctionnalités et des pull requests.

À quoi cela ressemble, où fA est un commit avec la fonctionnalité A, et fB est un commit avec la fonctionnalité B:

            fA   fC (bad commit, don't merge)
           /  \ /
master ----A----B----C
                \  /
                 fB

Les demandes d'extraction sont associées aux fonctionnalités de GitHub, mais tout ce que je veux dire, c'est que quelqu'un a la responsabilité de fusionner les branches de fonctionnalités dans master.

MattJenko
la source