web-dev-qa-db-fra.com

git - ignorer des commits spécifiques lors de la fusion

Cela fait environ un an que j'utilise Git et je trouve ça fantastique, mais je viens tout juste de commencer une deuxième version du projet et de créer une nouvelle branche. Je me bats un peu avec la meilleure façon de gérer les choses à l'avenir.

J'ai deux branches appelées par exemple master10 (pour v1) et master20 (pour v2). J'ai corrigé des bogues dans v1 sur la branche master10 et développé de nouvelles fonctionnalités de master20. Chaque fois que je corrige un bogue, je le fusionne en v2 en vérifiant master20 et en faisant git merge master10. Jusqu'ici tout va bien.

Maintenant, cependant, j'ai apporté une modification à la v1 que je ne souhaite pas utiliser dans la v2, mais je souhaite continuer à fusionner d'autres correctifs. Comment puis-je dire à Git de sauter ce commit (ou une plage de commits), mais que, à l'avenir, je souhaite toujours fusionner d'autres corrections de bugs.

J'ai pensé git rebase pourrait être ce dont j'avais besoin, mais j'ai lu la doc et ma tête a failli exploser.

Je pense que ce que je veux, c'est quelque chose comme une commande "git sync" qui indique à git que deux branches sont maintenant synchronisées et que, dans le futur, fusionnent uniquement les commits à partir de ce point de synchronisation.

Toute aide appréciée.

185
Brad Robinson

Par exemple, si vous souhaitez fusionner la plupart des commits de la branche "maint" sur "maître", vous pouvez le faire. Cela nécessite un peu de travail - comme mentionné ci-dessus, le cas d'utilisation habituel est de fusionner tout depuis une branche - mais il arrive parfois que vous changiez une version qui ne devrait pas être intégrée (peut-être que le code déjà été remplacé en maître), alors comment représentez-vous cela? Voici...

Supposons donc que 5 modifications ont été appliquées à maint et que l’un d’eux (maint ~ 3) ne soit pas fusionné avec le maître, bien que tous les autres le soient. Vous faites cela en trois étapes: fusionnez tout ce qui précède, indiquez à git de marquer maint ~ 3 comme étant fusionné, même si ce n'est pas le cas, puis fusionnez le reste. La magie c'est:

bash <master>$ git merge maint~4
bash <master>$ git merge -s ours maint~3
bash <master>$ git merge maint

La première commande fusionne tout avant votre maintenance gênante commet sur le maître. Le message de journal de fusion par défaut expliquera que vous fusionnez "branche 'maint' (première partie)".

La deuxième commande fusionne le commit ~ maint 3 difficile, mais l'option "-sours" indique à git d'utiliser une "stratégie de fusion" spéciale qui fonctionne en conservant simplement l'arborescence dans laquelle vous fusionnez et en ignorant le commit (s). ) vous fusionnez complètement. Mais il effectue toujours un nouvel engagement de fusion avec HEAD et maint ~ 3 en tant que parents, de sorte que le graphique de révision indique maintenant que maint ~ 3 est fusionné. Par conséquent, vous souhaiterez probablement utiliser le L'option -m permet également de "fusionner", pour expliquer que cette maintenance de ~ 3 est ignorée!

La dernière commande fusionne simplement le reste de maint (maint ~ 2..maint) dans master afin que vous soyez tous synchronisés à nouveau.

272
araqnid

IMHO, la chose la plus logique à faire est de fusionner tout, puis utiliser git revert (commit_you_dont_want) pour le supprimer.

Exemple:

git merge master
git revert 12345678

Si vous avez plusieurs validations "à ignorer", ou si vous souhaitez modifier le message de retour:

git merge master
git revert -n 123456
git revert -n abcdef
git commit -m "... Except commits 123456 and abcdef"

Ensuite, votre histoire peut ressembler à:

| ... Except 123456 and abcdef
|\ Merge branch 'master' into 'your_branch'

Si vous avez des conflits impliquant UNIQUEMENT ces commits "to-ignore", vous pouvez utiliser:

git merge master -X ours

Donc, votre version persistera sur l'autre. Même sans message d'erreur, vous pouvez toujours "annuler" ces commises non désirées, car d'autres modifications peuvent ne pas entrer en conflit et vous ne les souhaitez toujours pas.

Si vous avez des conflits impliquant UNIQUEMENT les validations "à ignorer", vous devez les résoudre manuellement et vous devrez probablement les résoudre à nouveau lors de la restauration.

32
Alexandre T.

Les commits incluent l'ascendance. Vous ne pouvez pas fusionner un commit sans fusionner des commits précédents.

Vous pouvez les choisir, bien sûr. C'est un bon flux lorsque vous avez une branche en mode maintenance.

16
Dustin

Cela ressemble à un cas classique pour 'git cherry-pick' https://git-scm.com/docs/git-cherry-pick il fait exactement à quoi ça ressemble

6
Gilbert

Une sorte de publicité à mon projet qui englobe fondamentalement le processus décrit par @araqnid.

C'est une sorte d'aide qui introduit le flux GIT suivant:

  • il y a une notification quotidienne/hebdomadaire sur les fusions en attente des branches de maintenance vers les branches dev/master
  • le responsable de la succursale vérifie le statut et décide lui-même si tous les validations sont requises et en bloque certains ou demande aux développeurs de les bloquer eux-mêmes. En fin de compte, la branche maintenance est fusionnée dans la upsteam.

Une citation de la page du projet:

Selon le flux de travail, il est possible d'avoir des branches de maintenance ou spécifiques au client avec la branche principale. Ces branches sont aussi appelées branches LTS.

Souvent, les correctifs logiciels vont dans les branches où le bogue a été signalé, puis le commit est fusionné dans la branche principale.

En règle générale, toutes les branches sont parfaitement synchronisées avec le maître, c’est-à-dire que vous souhaitez voir un delta clair entre une branche et un maître en particulier, afin de comprendre si le maître contient toutes les fonctionnalités et corrections de bugs.

Cependant, parfois, vous ne souhaitez pas que des commits particuliers soient spécifiques au client et ne doivent pas être visibles par les autres utilisateurs. Ou bien votre branche maîtresse a divergé sur le fait qu’il faut une approche complètement différente pour résoudre le problème, ou même mieux, le problème n’est plus présent dans cette région.

De plus, en cas de sélection dans le maître dans la branche de maintenance, la validation résultante doit être bloquée dans le maître.

2
Dmytro

Plutôt que revert ou cherry-pick dans ce cas, vous devez demander à git de considérer les modifications que vous ignorez comme étant plus anciennes que celles que vous avez apportées.

Alors:

  1. fusionner le dernier commit avant les commits que vous voulez ignorer. Ce sera, bien sûr, fusionner tous les commits avant. git merge ccc
  2. fusionner les commits que vous voulez ignorer. git merge fff --no-commit
  3. mettez en scène toutes les fusions, annulez toutes les modifications, annulez toutes les modifications. (Peut-être qu'il y a des commandes infaillibles pour cela, mais je ferais juste cette partie dans une interface utilisateur - mais vous savez comment faire)
  4. terminer la fusion vide git merge --continue
  5. fusionner les commits APRÈS celui que vous vouliez ignorer. git merge source-branch-head

Après l’étape 4, git considérera votre branche plus récente que celle validée, puisque vous l’avez déjà traitée (en choisissant de conserver VOS versions des choses).

0
Jason Kleban

Créez une troisième branche pour les modifications souhaitées dans master10 mais pas dans master20. Considérez toujours master10 comme votre "maître", la branche la plus stable de toutes. La branche avec laquelle toutes les autres branches veulent rester synchronisées à tout moment.

0
wilhelmtell