Dans git, quelle est la différence entre fusion --squash et rebase?

363

Je suis nouveau sur git et j'essaie de comprendre la différence entre un squash et un rebase. Si je comprends bien, vous effectuez un squash lors d'un rebase.

GiH
la source

Réponses:

360

Les deux git merge --squashet git rebase --interactivepeuvent produire un commit "écrasé".
Mais ils servent à des fins différentes.

produira un commit écrasé sur la branche de destination, sans marquer de relation de fusion.
(Remarque: il ne produit pas de commit tout de suite: vous en avez besoin d'un supplémentaire git commit -m "squash branch")
Ceci est utile si vous souhaitez supprimer complètement la branche source, en partant de (schéma tiré de la question SO ):

 git checkout stable

      X                   stable
     /                   
a---b---c---d---e---f---g tmp

à:

git merge --squash tmp
git commit -m "squash tmp"

      X-------------------G stable
     /                   
a---b---c---d---e---f---g tmp

puis en supprimant la tmpbranche.


Remarque: git mergea une --commitoption , mais ne peut pas être utilisée avec --squash. Il n'a jamais été possible d'utiliser --commitet --squashensemble.
Depuis Git 2.22.1 (Q3 2019), cette incompatibilité est rendue explicite:

Voir commit 1d14d0c (24 mai 2019) par Vishal Verma ( reloadbrain) .
(Fusionné par Junio ​​C Hamano - gitster- en commit 33f2790 , 25 juil.2019 )

merge: refuser --commitavec--squash

Auparavant, lorsqu'il --squashétait fourni, ' option_commit' était silencieusement abandonné. Cela aurait pu surprendre un utilisateur qui a tenté de remplacer le comportement sans validation de squash en utilisant --commitexplicitement.

git/git builtin/merge.c#cmd_merge() comprend désormais:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

rejoue une partie ou la totalité de vos commits sur une nouvelle base, vous permettant de squash (ou plus récemment de "réparer", voir cette question SO ), en allant directement à:

git checkout tmp
git rebase -i stable

      stable
      X-------------------G tmp
     /                     
a---b

Si vous choisissez d'écraser tous les commits de tmp(mais, contrairement à merge --squash, vous pouvez choisir d'en rejouer certains et d'en écraser d'autres).

Les différences sont donc:

  • squashne touche pas à votre branche source ( tmpici) et crée un seul commit où vous le souhaitez.
  • rebasevous permet de continuer sur la même branche source (toujours tmp) avec:
    • une nouvelle base
    • une histoire plus propre
VonC
la source
12
Gest c--d--e--f--gécrasé ensemble?
Wayne Conrad
9
@Wayne: oui, G dans ces exemples représente les tmpcommits écrasés ensemble.
VonC
3
@ Th4wn: Puisque Git raisonne avec des instantanés d'un projet tout, Gne représentera pas le même contenu que g, en raison des changements introduits par X.
VonC
1
@VonC: pas sûr de ce dernier commentaire. Si vous en avez un git merge --no-ff tempau lieu de git merge --squash temp, alors vous obtenez un historique plus compliqué, mais vous pouvez également faire des choses comme git revert e, beaucoup plus facilement. C'est une histoire désordonnée, mais honnête et pragmatique, et la branche principale reste assez propre.
naught101
2
@ naught101 Je suis d'accord. Comme expliqué dans stackoverflow.com/a/7425751/6309 , il s'agit également de ne pas casser git bisectou git blamelorsqu'il est utilisé trop souvent (comme dans git pull --no-ff: stackoverflow.com/questions/12798767/… ). Il n'y a pas une approche de toute façon, c'est pourquoi cet article en décrit trois ( stackoverflow.com/questions/9107861/… )
VonC
184

Fusionner les validations: conserve toutes les validations dans votre branche et les entrelace avec les validations sur la branche de baseentrez la description de l'image ici

Fusionner Squash: conserve les modifications mais omet l'individu commet de l'historique entrez la description de l'image ici

Rebase: Cela déplace la branche d'entité entière pour commencer à l'extrémité de la branche principale, incorporant efficacement toutes les nouvelles validations dans master

entrez la description de l'image ici

Plus ici

Md Ayub Ali Sarker
la source
J'ai trouvé cela plus clair que la réponse acceptée. Je vous remercie!
payne il y a
81

Merge squash fusionne un arbre (une séquence de commits) en un seul commit. Autrement dit, il écrase toutes les modifications apportées dans n commits en un seul commit.

La refondation est une nouvelle base, c'est-à-dire le choix d'une nouvelle base (commit parent) pour un arbre. Peut-être que le terme mercuriel pour cela est plus clair: ils l'appellent transplantation parce que c'est juste que: choisir un nouveau terrain (parent commit, root) pour un arbre.

Lorsque vous effectuez un rebase interactif, vous avez la possibilité de supprimer, sélectionner, modifier ou ignorer les commits que vous allez rebaser.

J'espère que c'était clair!

Mauricio Scheffer
la source
7
Quand dois-je rebaser et quand dois-je écraser?
Martin Thoma
31

Commençons par l'exemple suivant:

entrez la description de l'image ici

Nous avons maintenant 3 options pour fusionner les modifications de la branche d'entité dans la branche principale :

  1. Fusionner les validations
    Gardera tous les historiques des validations de la branche de fonctionnalité et les déplacera dans la branche principale
    Ajoutera une validation factice supplémentaire.

  2. Rebase and merge
    Ajoute tous les historiques de validation de la branche de fonctionnalité à l'avant de la branche master
    N'ajoute PAS de validation fictive supplémentaire.

  3. Squash and merge
    regroupera toutes les validations de branche de fonctionnalité en une seule validation, puis les ajoutera à l'avant de la branche principale
    ajoutera une validation factice supplémentaire.

Vous pouvez voir ci-dessous comment la branche principale s'occupera de chacun d'eux.

entrez la description de l'image ici

Dans tous les cas:
nous pouvons SUPPRIMER en toute sécurité la branche de fonctionnalité .

ahmednabil88
la source
1
pouvez-vous expliquer ce qu'est un commit factice dans la 2ème photo ?? Je suis un débutant en git.
Yusuf
1
@Yusuf, c'est juste un commit supplémentaire qui contient les deux mises à jour des branches, c'est le message de commit par défaut = "Megre branche XYZ into master"
ahmednabil88