Comment utiliser git merge --squash?

1210

J'ai un serveur Git distant, voici le scénario que je souhaite effectuer:

  • Pour chaque bug / fonctionnalité, je crée une branche Git différente

  • Je continue de valider mon code dans cette branche Git avec des messages Git non officiels

  • Dans le référentiel supérieur, nous devons faire un commit pour un bug avec le message officiel Git

Alors, comment puis-je fusionner ma branche vers une branche distante afin qu'ils obtiennent un seul commit pour tous mes enregistrements (je veux même fournir un message de commit pour cela)?

SunnyShah
la source
1
Je ne sais pas si je vous ai complètement compris, mais vous voudrez peut-être une "fusion de poulpe".
MatrixFrog
27
J'utilise généralement git rebase -i pour réduire toutes mes validations en une seule validation et réécrire le message de validation. Ensuite, je l'envoie en amont.
Edward Falk
17
git merge --squashfait tout sur la ligne de commande en un seul coup et vous espérez juste que cela fonctionne. git rebase -iaffiche un éditeur et vous permet d'affiner le rebase. C'est plus lent, mais vous pouvez voir ce que vous faites. En outre, il existe une différence entre rebaser et fusion qui sont un peu trop impliquées pour être abordées dans un commentaire.
Edward Falk du
4
le problème avec toutes ces réponses est que vous devez être localement sur la branche principale et exécuter la commande merge --squash ... Je veux exécuter la fusion --squash à partir de la branche de fonction et non de la branche principale ... pour que quand j'ai fini, je peux pousser la branche de fonctionnalité vers la télécommande et soumettre un PR, est-ce possible?
Alexander Mills
2
@AlexanderMills, je pense que vous avez juste besoin d'une deuxième branche de fonctionnalité (clonée à partir de la branche principale). Faites merge --squashde l'ancienne vers la nouvelle, puis fusionnez la nouvelle branche pour la maîtriser. L'ancienne branche devient obsolète.
Gyromite

Réponses:

2002

Supposons que votre branche de correction de bogues soit appelée bugfixet que vous souhaitiez la fusionner en master:

git checkout master
git merge --squash bugfix
git commit

Cela prendra toutes les bugfixvalidations de la branche, les écrasera en 1 commit et les fusionnera avec votre masterbranche.


Explication :

git checkout master

Bascule vers votre mastersuccursale.

git merge --squash bugfix

Prend toutes les validations de la bugfixbranche et les fusionne avec votre branche actuelle.

git commit

Crée une validation unique à partir des modifications fusionnées.

L'omission du -mparamètre vous permet de modifier un projet de message de validation contenant tous les messages de vos validations écrasées avant de finaliser votre validation.

abyx
la source
222
Si vous souhaitez conserver les références aux anciens messages de validation, vous pouvez écrire git commit(sans -mparam) et vous pourrez modifier un message de validation rédigé contenant tous les messages de validation que vous avez écrasés.
Alex
12
Vous pouvez obtenir le même résultat git commit --amend -m '...'plus tard.
Janusz Lenar
19
Si des conflits de fusion se produisent et que vous résolvez ces conflits, git commitle message de validation utile ne contenant plus tous les messages de validation que vous avez écrasés ne s'affichera plus. Dans ce cas, essayez git commit --file .git/SQUASH_MSG(via stackoverflow.com/a/11230783/923560 ).
Abdull
23
Gardez à l'esprit que le squash attribuera par défaut les validations au squasher . Pour conserver l'auteur original, vous devez le spécifier explicitement ainsi:git commit -a --author="Author" --message="Issue title #id"
gaborous
5
git merge --squashvous permet de créer un commit unique au-dessus de la branche actuelle dont l'effet est le même que la fusion d'une autre branche. Mais cela ne produira pas l'enregistrement de fusion, ce qui signifie que votre pull-request en tant que résultat n'aurait aucun changement, mais ne sera pas marqué comme fusionné! Donc, vous aurez juste besoin de supprimer cette branche pour le faire.
am0wa
129

Ce qui a finalement clarifié cela pour moi, c'est un commentaire montrant que:

git checkout main
git merge --squash feature

est l'équivalent de faire:

git checkout feature
git diff main > feature.patch
git checkout main
patch -p1 < feature.patch
git add .

Lorsque je veux fusionner une branche de fonctionnalité avec 105 (!!) validations et les avoir toutes écrasées en une seule, je ne veux pas git rebase -i origin/masterparce que je dois résoudre séparément les conflits de fusion pour chacune des validations intermédiaires (ou au moins celles qui git ne peut pas se comprendre). L'utilisation git merge --squashme donne le résultat que je veux, d'un seul commit pour fusionner une branche de fonctionnalité entière. Et, je n'ai besoin que de faire au plus une résolution manuelle des conflits.

Dan Kohn
la source
75
Je suggère fortement d'effectuer la fusion dans la branche de fonctionnalité en premier git merge master, puis seulement git merge --squash featuredans la branche principale.
dotancohen
8
@dotancohen Désolé de récupérer un vieux commentaire :) Qu'est-ce qui est gagné en fusionnant dans la branche de fonctionnalité avant d'effectuer git merge --squash featurede la branche principale?
bitsmack
57
Vous souhaitez d'abord fusionner le maître dans la branche de fonctionnalité et gérer les correctifs manuels dans votre branche de fonctionnalité. Cela vous permet également d'exécuter des tests et de vous assurer que votre branche de fonctionnalité fonctionne correctement. Ensuite, vous avez la garantie de pouvoir fusionner automatiquement votre branche de fonctionnalité en maître.
Dan Kohn
4
@dankohn Je vous suggère d'ajouter l'explication dans votre commentaire ci-dessus dans votre réponse.
guntbert
3
@bitsmack: vous fusionneriez d'abord le maître dans la fonctionnalité. Cela vous donne la possibilité de résoudre les conflits sur la fonctionnalité avant de fusionner la fonctionnalité en maître
Mike
97

Vous souhaitez fusionner avec l'option de squash. C'est si vous voulez le faire une branche à la fois.

git merge --squash feature1

Si vous souhaitez fusionner toutes les branches en même temps que les validations simples, rebasez d'abord de manière interactive et écrasez chaque fonctionnalité, puis fusionnez le poulpe:

git checkout feature1
git rebase -i master

Squash dans un commit puis répétez pour les autres fonctionnalités.

git checkout master
git merge feature1 feature2 feature3 ...

Cette dernière fusion est une "fusion de poulpe" car elle fusionne beaucoup de branches à la fois.

J'espère que cela t'aides

Adam Dymitruk
la source
3
Pourquoi rebasez-vous?
Umair A.
12
@UmairAshraf c'est un rebase interactif qui vous donne la possibilité de faire un squash au sein de votre branche.
andho
1
Le reconditionnement est une mauvaise idée. Ne pas rebaser les commits déjà publiés
Sebi2020
1
@ Sebi2020 git merge --squash va rebaser vos commits déjà publiés d'une manière pire qu'un rebase interactif. Un rebase interactif (sur une branche de fonctionnalité) n'entraîne pas ou peu d'effets indésirables.
xiix
1
@xiix Cela n'est vrai que si vous êtes le seul à travailler avec la branche de fonctionnalité. Ce n'est pas une hypothèse que vous pouvez faire. Je recommande de lire les pages liées au rebasage sur Git-SCM . Il indique " Ne pas rebaser les validations qui existent en dehors de votre référentiel et les gens peuvent avoir basé leur travail dessus. " nature de git) vous ne devriez pas faire ça.
Sebi2020
23

Si vous l'avez déjà git merge bugfixactivé main, vous pouvez réduire votre commit de fusion en un seul avec:

git reset --soft HEAD^1
git commit
qwertzguy
la source
git reset --soft HEAD^1semble annuler la dernière validation effectuée avant la fusion, du moins dans le cas où la fusion est une avance rapide.
Jesper Matthiesen
@JesperMatthiesen en cas d'avance rapide, vous n'obtenez pas de validation de fusion, alors vous le feriez git reset --soft HEAD^<number-of-commits-to-squash>.
qwertzguy
Cela m'a aidé à tout écraser en un seul commit après une fusion en aval.
killjoy
18

Fusionner la newFeaturebranche masteravec un commit personnalisé:

git merge --squash newFeature && git commit -m 'Your custom commit message';

Si à la place, vous

git merge --squash newFeature && git commit

vous obtiendrez un message de validation qui comprendra toutes les validations de newFeaturebranche, que vous pouvez personnaliser.

Je l'explique en détail ici: https://youtu.be/FQNAIacelT4

Vagelis Prokopiou
la source
10

Je sais que cette question ne concerne pas spécifiquement Github, mais puisque Github est si largement utilisé et que c'est la réponse que je cherchais, je la partagerai ici.

Github a la possibilité d'effectuer des fusions de squash, selon les options de fusion activées pour le référentiel.

Si les fusions de squash sont activées, l'option "Squash and merge" devrait apparaître dans la liste déroulante sous le bouton "Merge".

Capture d'écran de la fonction Github "Squash and merge"

Aaron
la source
GitHub utilise l'e-mail par défaut associé à votre compte. Si vous avez plusieurs adresses e-mail et que vous devez en utiliser une secondaire, vous ne pouvez pas utiliser GH UI.
Luca Guidi
4

Supposons que vous ayez travaillé dans feature / task1 avec plusieurs validations.

  1. Accédez à votre branche de projet (project / my_project)

    git checkout project/my_project
    
  2. Créer une nouvelle branche (feature / task1_bugfix)

    git checkout -b feature/task1_bugfix
    
  3. Marge avec l' --squashoption

    git merge --squash feature/task1
    
  4. Créer un seul commit

    git commit -am "add single comments"
    
  5. Poussez votre branche

    git push --set-upstream origin feature/task1_bugfix
    
Farid Haq
la source
1

Pour Git

Créer une nouvelle fonctionnalité

via Terminal / Shell:

git checkout origin/feature/<featurename>
git merge --squash origin/feature/<featurename>

Cela ne le valide pas, vous permet de le consulter en premier.

Ensuite, validez et terminez la fonctionnalité de cette nouvelle branche, et supprimez / ignorez l'ancienne (celle que vous avez développée).

Demian Berisford-Maynard
la source
@Melebius La seule référence à "SourceTree" est dans votre phrase, s'il s'agissait d'une balise ou d'une question précédente: elle n'existe plus.
Jordan Stefanelli
1
@JordanStefanelli SourceTree a été utilisé dans la version originale de cette réponse . Merci d'avoir signalé que le problème était résolu!
Melebius
1

si vous obtenez une erreur: la validation n'est pas possible car vous avez des fichiers non fusionnés.

git checkout master
git merge --squash bugfix
git add .
git commit -m "Message"

correction de tous les fichiers de conflit

git add . 

vous pouvez également utiliser

git add [filename]
ResUta
la source
0

Pour écraser votre succursale locale avant de la pousser:

  1. extraire la branche en question sur laquelle travailler si elle n'est pas déjà extraite.

  2. Trouvez le sha du plus ancien commit que vous souhaitez conserver.

  3. Créer / extraire une nouvelle branche (tmp1) à partir de ce commit.

    git checkout -b tmp1 <sha1-of-commit>

  4. Fusionnez la branche d'origine dans la nouvelle écrasement.

    git merge --squash <original branch>

  5. Validez les modifications qui ont été créées par la fusion, avec un message de validation récapitulatif.

    git commit -m <msg>

  6. Découvrez la branche d'origine que vous souhaitez écraser.

    git checkout <branch>

  7. Réinitialisez le commit d'origine que vous souhaitez conserver.

    git reset --soft <sha1>

  8. Rebase cette branche en fonction de la nouvelle branche tmp1.

    git rebase tmp1

  9. C'est tout - supprimez maintenant la branche temporaire tmp1 une fois que vous êtes sûr que tout va bien.

Jool
la source
0

Vous pouvez utiliser l'outil que j'ai créé pour faciliter ce processus: git-squash . Par exemple, pour écraser toutes les validations sur la branche de fonctionnalité qui a été branchée à partir de la branche principale, écrivez:

git squash master
git push --force
sheerun
la source