Quand utilisez-vous git rebase au lieu de git merge?

Quand est-il recommandé d’utiliser git rebase vs git merge ?

Dois-je encore fusionner après un rebase réussi?

Version courte

  • Fusionner prend tous les changements dans une twig et les fusionne dans une autre twig dans un commit.
  • Rebase dit que je veux que le point auquel je suis ramifié passe à un nouveau sharepoint départ

Alors, quand utilisez-vous l’un ou l’autre?

Fusionner

  • Disons que vous avez créé une twig dans le but de développer une fonctionnalité unique. Lorsque vous souhaitez rétablir ces modifications dans la firebase database, vous souhaiterez probablement les fusionner (vous ne vous souciez pas de la gestion de tous les commits provisoires).

Rebase

  • Un deuxième scénario serait si vous avez commencé à faire du développement et qu’un autre développeur a apporté une modification sans rapport. Vous souhaitez probablement tirer puis rebaser pour baser vos modifications sur la version actuelle du repository.

C’est simple, avec rebase vous dites d’utiliser une autre twig comme nouvelle base pour votre travail.

Si vous avez par exemple un master twig et que vous créez une twig pour implémenter une nouvelle fonctionnalité, dites-lui que vous l’ cool-feature , bien sûr, la twig principale est la base de votre nouvelle fonctionnalité.

Maintenant, à un moment donné, vous souhaitez append la nouvelle fonctionnalité que vous avez implémentée dans la twig principale. Vous pouvez simplement passer en mode master et fusionner la twig cool-feature :

 $git checkout master $git merge cool-feature 

mais de cette façon, un nouveau commit factice est ajouté, si vous voulez éviter l’historique des spaghettis, vous pouvez rebaser :

 $git checkout cool-feature $git rebase master 

puis le fusionner en master :

 $git checkout master $git merge cool-feature 

Cette fois-ci, puisque la twig de sujet a les mêmes commits de master plus les commits avec la nouvelle fonctionnalité, la fusion sera juste une avance rapide.

Pour compléter ma propre réponse mentionnée par TSamper ,

  • une rebase est souvent une bonne idée à faire avant une fusion, car l’idée est d’intégrer dans votre twig le travail de la twig B sur laquelle vous allez fusionner.
    Mais encore une fois, avant de fusionner, vous résolvez tout conflit dans votre twig (ex: “rebase”, comme dans “replay mon travail dans ma twig à partir d’un point récent de la twig B )
    Si cela est fait correctement, la fusion ultérieure de votre twig à la twig B peut être accélérée.

  • une fusion a un impact direct sur la twig de destination B , ce qui signifie que les fusions doivent être sortingviales, sinon cette twig B peut être longue pour revenir à un état stable (le temps pour vous de résoudre tous les conflits)


le sharepoint fusion après une rebase?

Dans le cas que je décris, je rebase B sur ma twig, juste pour avoir la possibilité de rejouer mon travail depuis un point plus récent de B , mais en restant dans ma twig.
Dans ce cas, une fusion est toujours nécessaire pour amener mon travail “rejoué” sur B

L’autre scénario ( décrit dans Git Ready, par exemple) consiste à placer votre travail directement dans B via un rebase (qui conserve tous vos bons commits, ou même vous permet de les réorganiser via un rebase interactif).
Dans ce cas (où vous vous rebase en étant dans la twig B), vous avez raison: aucune fusion supplémentaire n’est nécessaire:

Un arbre git par défaut lorsque nous n’avons ni fusionné ni rebasé

rebase1

nous obtenons en rebasant:

rebase3

Ce deuxième scénario est tout au sujet de: comment puis-je ramener de nouvelles fonctionnalités dans master.

Mon point, en décrivant le premier scénario de rebase, est de rappeler à tout le monde qu’une rebase peut également être utilisée comme une étape préliminaire à cela (c’est-à-dire «ramener la nouvelle fonctionnalité dans le master»).
Vous pouvez utiliser rebase pour mettre en premier le maître “in” dans la twig nouveauté: la rebase rejouera new-feature valid du HEAD master , mais toujours dans la twig nouveauté, déplaçant ainsi le sharepoint départ d’une ancienne validation maître à HEAD-master .
Cela vous permet de résoudre tous les conflits dans votre twig (c’est-à-dire, isolément, tout en permettant à master de continuer à évoluer en parallèle si votre étape de résolution de conflit prend trop de temps).
Ensuite, vous pouvez basculer vers le mode maître et fusionner la new-feature (ou rebaser la new-feature sur le master si vous souhaitez conserver les validations effectuées dans votre twig new-feature ).

Alors:

  • “rebase vs. merge” peut être considéré comme deux manières d’importer une œuvre sur, par exemple, master .
  • Mais “rebase puis merge” peut être un workflow valide pour résoudre d’abord les conflits de manière isolée, puis ramener votre travail.

Beaucoup de réponses ici indiquent que la fusion transforme tous vos commits en un seul et suggèrent donc d’utiliser le rebase pour préserver vos commits. Ceci est une erreur. Et une mauvaise idée si vous avez déjà poussé vos commits .

Fusionner n’efface pas vos commits. Fusionner préserve l’histoire! (regardez simplement gitk) Rebase réécrit l’historique, ce qui est une mauvaise chose après l’avoir poussée .

Utilisez la fusion – pas rebase chaque fois que vous avez déjà poussé.

Voici Linus (auteur de git) . C’est une très bonne lecture. Ou vous pouvez lire ma propre version de la même idée ci-dessous.

Rebasing une twig sur master:

  • fournit une idée incorrecte de la façon dont les commits ont été créés
  • pollue maître avec un tas de commits intermédiaires qui n’ont peut-être pas été bien testés
  • pourrait effectivement introduire des sauts de build sur ces commits intermédiaires en raison des modifications apscopes à la maîsortingse entre la création de la twig de sujet d’origine et le moment où elle a été rebasée.
  • rend difficile la recherche de bonnes places en master.
  • Les horodatages sur les validations ne sont pas alignés sur leur ordre chronologique dans l’arborescence. Donc, vous verriez que commit A précède le commit B dans master, mais que commit B a été créé en premier. (Quelle?!)
  • Produit plus de conflits car les commits individuels dans la twig de sujet peuvent impliquer chacun des conflits de fusion qui doivent être résolus individuellement (Plus d’informations sur ce qui s’est passé dans chaque engagement).
  • est une réécriture de l’histoire. Si la twig rebasée a été poussée n’importe où (partagée avec quelqu’un d’autre que vous-même), alors vous avez foutu tout le monde qui a cette twig depuis que vous avez réécrit l’histoire.

En revanche, fusionner une twig de sujet en master:

  • conserve l’historique de la création des twigs de la rubrique, y compris des fusions de la twig maître à la twig du sujet pour la garder à jour. Vous avez une idée précise du code avec lequel le développeur travaillait lors de la construction.
  • master est une twig composée principalement de fusions, et chacune de ces validations de fusion sont généralement de «bons points» dans l’histoire qui peuvent être vérifiées, car c’est là que la twig était prête à être intégrée.
  • Tous les commits individuels de la twig de sujet sont conservés, y compris le fait qu’ils se trouvaient dans une twig de sujet. Il est donc naturel d’isoler ces modifications et de les explorer au besoin.
  • les conflits de fusion ne doivent être résolus qu’une seule fois (au sharepoint fusion), donc les modifications de validation intermédiaires effectuées dans la twig de sujet ne doivent pas être résolues de manière indépendante.
  • peut être fait plusieurs fois en douceur. Si vous intégrez périodiquement votre twig de sujet à la maîsortingse, les gens peuvent continuer à développer la twig du sujet et continuer à fusionner indépendamment.

TL; DR

En cas de doute, utilisez la fusion.

Réponse courte

Les seules différences entre une rebase et une fusion sont les suivantes:

  • L’arborescence résultante de l’historique (généralement visible uniquement lorsque l’on regarde un graphe de validation) est différente (l’une aura des twigs, l’autre non).
  • La fusion créera généralement un commit supplémentaire (par exemple un noeud dans l’arborescence).
  • Fusionner et rebaser traitera les conflits différemment. Rebase présentera des conflits que l’un commettra à un moment où la fusion les présentera tous en même temps.

Donc, la réponse courte est de choisir la fusion ou la réorganisation en fonction de ce que vous voulez que votre historique ressemble .

Longue réponse

Il y a quelques facteurs à considérer lors du choix de l’opération à utiliser.

La twig à laquelle vous apportez des modifications est-elle partagée avec d’autres développeurs externes à votre équipe (par exemple, open source, public)?

Si c’est le cas, ne rebase pas. Rebase détruit la twig et ces développeurs auront des référentiels cassés / incohérents à moins d’utiliser git pull --rebase . C’est un bon moyen de contrarier rapidement les autres développeurs.

Quelle est la compétence de votre équipe de développement?

Rebase est une opération destructive. Cela signifie que si vous ne l’appliquez pas correctement, vous risquez de perdre le travail engagé et / ou de briser la cohérence des référentiels des autres développeurs.

J’ai travaillé sur des équipes où les développeurs venaient tous à une époque où les entresockets pouvaient se permettre de consacrer du personnel à la création et à la fusion. Ces développeurs ne connaissent pas beaucoup Git et ne veulent pas en savoir beaucoup. Dans ces équipes, je ne risquerais pas de recommander un rebasement pour une raison quelconque.

La twig elle-même représente-t-elle une information utile

Certaines équipes utilisent le modèle twig par fonctionnalité, chaque twig représentant une fonctionnalité (ou un correctif ou une sous-fonctionnalité, etc.). Dans ce modèle, la twig aide à identifier les ensembles de validations associées. Par exemple, on peut rapidement annuler une fonctionnalité en annulant la fusion de cette twig (pour être juste, il s’agit d’une opération rare). Ou bien différez une fonctionnalité en comparant deux twigs (plus courantes). Rebase détruirait la twig et cela ne serait pas simple.

J’ai également travaillé sur des équipes utilisant le modèle de twig par développeur (nous y sums tous allés). Dans ce cas, la twig elle-même ne transmet aucune information supplémentaire (le commit a déjà l’auteur). Il n’y aurait pas de mal à rebaser.

Voulez-vous revenir sur la fusion pour une raison quelconque?

Renverser (comme en défaisant) une rebase est considérablement difficile et / ou impossible (si la rebase avait des conflits) par rapport à la restauration d’une fusion. Si vous pensez qu’il y a une chance que vous vouliez revenir, utilisez la fusion.

Travaillez-vous en équipe? Si oui, êtes-vous prêt à adopter une approche tout ou rien sur cette twig?

Les opérations de rebase doivent être extraites avec un git pull --rebase correspondant. Si vous travaillez par vous-même, vous pouvez vous souvenir de ce que vous devez utiliser au moment opportun. Si vous travaillez dans une équipe, cela sera très difficile à coordonner. C’est pourquoi la plupart des workflows de rebase recommandent l’utilisation de rebase pour toutes les fusions (et git pull --rebase pour tous les tirages).

Mythes communs

La fusion détruit l’histoire (les courges commettent)

En supposant que vous avez la fusion suivante:

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

Certaines personnes diront que la fusion “détruit” l’historique des validations, car si vous ne regardiez que le journal de la twig principale (A-D), vous manqueriez les messages de validation importants contenus dans B et C.

Si c’était vrai, nous n’aurions pas de questions comme celle-ci . Fondamentalement, vous verrez B et C à moins que vous ne demandiez explicitement de les voir (en utilisant –first-parent). C’est très facile d’essayer par vous-même.

Rebase permet des fusions plus sûres / plus simples

Les deux approches fusionnent différemment, mais il n’est pas clair que l’une soit toujours meilleure que l’autre et que cela dépend du stream de travail du développeur. Par exemple, si un développeur a tendance à s’engager régulièrement (par exemple, s’il s’engage deux fois par jour lorsqu’il passe de travail à domicile), il peut y avoir beaucoup de commits pour une twig donnée. Beaucoup de ces commits peuvent ne pas ressembler au produit final (j’ai tendance à refactoriser mon approche une ou deux fois par fonctionnalité). Si quelqu’un d’autre travaillait sur un domaine de code connexe et qu’ils essayaient de modifier mes modifications, l’opération pourrait être assez fastidieuse.

Rebase est plus cool / plus sexy / plus professionnel

Si vous souhaitez alias rm to rm -rf pour “gagner du temps”, alors rebase est peut-être pour vous.

Mes deux centimes

Je pense toujours qu’un jour je rencontrerai un scénario où git rebase est l’outil génial qui résout le problème. Tout comme je pense que je vais rencontrer un scénario où Gog Reflog est un outil génial qui résout mon problème. Je travaille avec git depuis plus de cinq ans maintenant. Ça n’est pas arrivé

Les histoires désordonnées n’ont jamais vraiment été un problème pour moi. Je ne me contente pas de lire l’histoire de mon engagement comme un roman passionnant. La plupart du temps, j’ai besoin d’une histoire. Je vais utiliser git blame ou git bisect de toute façon. Dans ce cas, la validation de la fusion est réellement utile pour moi, car si la fusion a introduit le problème, il s’agit d’une information significative pour moi.

Mise à jour (4/2017)

Je me sens obligé de mentionner que je me suis personnellement adouci à utiliser le rebase bien que mes conseils généraux soient toujours valables. J’ai récemment beaucoup interagi avec le projet Angular 2 Material . Ils ont utilisé rebase pour garder un historique de validation très propre. Cela m’a permis de voir très facilement ce qui avait été corrigé pour un défaut donné et si cette validation était incluse dans une version. C’est un bon exemple d’utilisation correcte de rebase.

Fusionner signifie: créer une nouvelle validation unique qui fusionne mes modifications dans la destination.

Rebase signifie: créer une toute nouvelle série de commits, en utilisant mon ensemble actuel de commits en tant qu’indices. En d’autres termes, calculez à quoi ressembleraient mes modifications si j’avais commencé à les utiliser à partir du moment où je les ai repensées. Par conséquent, après le rebase, vous devrez peut-être tester à nouveau vos modifications et, lors du rebase, vous pourriez avoir quelques conflits.

Compte tenu de cela, pourquoi voudriez-vous rebase? Juste pour garder l’historique de développement clair. Disons que vous travaillez sur la fonctionnalité X et que lorsque vous avez terminé, vous fusionnez vos modifications. La destination aura désormais un seul commit qui indiquerait quelque chose comme “Ajout de la fonctionnalité X”. Maintenant, au lieu de fusionner, si vous avez rebasé puis fusionné, l’historique de développement de la destination contiendrait tous les commits individuels dans une seule progression logique. Cela facilite considérablement la révision des modifications. Imaginez à quel point vous trouveriez difficile de passer en revue l’histoire du développement si 50 développeurs fusionnaient constamment diverses fonctionnalités.

Cela dit, si vous avez déjà poussé la twig sur laquelle vous travaillez en amont, vous ne devriez pas la rebaser, mais fusionner à la place. Pour les twigs qui n’ont pas été poussées en amont, rebase, teste et fusionne.

Une autre fois, vous voudrez peut-être rebaser lorsque vous voulez vous débarrasser des commits de votre twig avant de pousser en amont. Par exemple: les commits qui introduisent un code de débogage au début et d’autres commits sur ce code nettoient ce code. La seule façon de le faire est d’effectuer un rebase interactif: git rebase -i

MISE À JOUR: Vous souhaitez également utiliser rebase lorsque vous utilisez Git pour interfacer un système de contrôle de version qui ne prend pas en charge l’historique non linéaire (subversion par exemple). Lorsque vous utilisez le pont git-svn, il est très important que les modifications que vous fusionnez dans subversion soient une liste séquentielle des modifications en plus des modifications les plus récentes dans le tronc. Il n’y a que deux façons de faire cela: (1) Recréer manuellement les modifications et (2) Utiliser la commande rebase, qui est beaucoup plus rapide.

UPDATE2: Une autre façon de penser à un rebase est qu’il permet une sorte de mappage de votre style de développement au style accepté dans le référentiel auquel vous vous engagez. Disons que vous aimez vous engager dans de petits morceaux minuscules. Vous en avez un qui s’engage à corriger une faute de frappe, on s’engage à se débarrasser du code inutilisé, etc. Au moment où vous avez terminé ce que vous devez faire, vous avez une longue série de commits. Maintenant, disons que le référentiel auquel vous vous engagez encourage de gros commits, donc pour le travail que vous faites, on pourrait s’attendre à une ou peut-être deux commits. Comment prenez-vous votre chaîne de commits et compressez-vous ce qui est attendu? Vous utiliseriez un rebase interactif et écraseriez vos minuscules commits en moins de gros morceaux. La même chose est vraie si l’inverse était nécessaire – si votre style comportait quelques gros commits, mais que le repo exigeait de longues chaînes de petits commits. Vous utiliseriez également une rebase pour le faire. Si vous aviez plutôt fusionné, vous avez maintenant greffé votre style de validation sur le référentiel principal. S’il y a beaucoup de développeurs, vous pouvez imaginer à quel point il serait difficile de suivre un historique avec plusieurs styles de validation différents après un certain temps.

UPDATE3: Faut Does one still need to merge after a successful rebase? Oui, vous La raison en est qu’une rebase implique essentiellement un “décalage” des commits. Comme je l’ai dit plus haut, ces commits sont calculés, mais si vous aviez 14 commits à partir du moment de l’emtwigment, en supposant que rien ne se passe avec votre rebase, vous serez 14 commits à l’avance la rebase est faite. Vous aviez une twig avant un rebase. Vous aurez une twig de la même longueur après. Vous devez encore fusionner avant de publier vos modifications. En d’autres termes, rebasez autant de fois que vous le souhaitez (encore une fois, seulement si vous n’avez pas poussé vos modifications en amont). Fusionnez seulement après que vous rebase.

avant fusion / rebase:

 A <- B <- C [master] ^ \ D <- E [branch] 

après git merge master :

 A <- B <- C ^ ^ \ \ D <- E <- F 

après git rebase master :

 A <- B <- C <- D' <- E' 

(A, B, C, D, E et F sont des commits)

Cet exemple et des informations beaucoup plus illustrées sur git sont disponibles ici: http://excess.org/article/2008/07/ogre-git-tutorial/

Cette phrase le comprend:

En général, le moyen d’obtenir le meilleur des deux mondes est de rebaser les modifications locales que vous avez faites, mais que vous n’avez pas encore partagées avant de les pousser afin de nettoyer votre histoire, sans jamais rebaser quelque chose.

Source: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge

Bien que la fusion soit certainement le moyen le plus simple et le plus courant d’intégrer les changements, ce n’est pas le seul: Rebase est un autre moyen d’intégration.

Comprendre fusionner un peu mieux

Lorsque Git effectue une fusion, il recherche trois validations:

  • (1) Common commit des ancêtres Si vous suivez l’historique de deux twigs dans un projet, elles ont toujours au moins un commit en commun: à ce stade, les deux twigs ont le même contenu et ont évolué différemment.
  • (2) + (3) Endpoints de chaque twig Le but d’une intégration est de combiner les états actuels de deux twigs. Par conséquent, leurs dernières révisions respectives présentent un intérêt particulier. La combinaison de ces trois engagements se traduira par l’intégration que nous visons.

Avance rapide ou fusion Commit

Dans des cas très simples, l’une des deux twigs n’a pas de nouveaux commits depuis le twigment – sa dernière validation est toujours l’ancêtre commun.

entrer la description de l'image ici

Dans ce cas, effectuer l’intégration est simple: Git peut simplement append tous les commits de l’autre twig au-dessus du commit commun ancêtre. Dans Git, cette forme d’intégration la plus simple est appelée fusion rapide. Les deux twigs partagent alors exactement la même histoire.

entrer la description de l'image ici

Dans beaucoup de cas, cependant, les deux twigs ont progressé individuellement. entrer la description de l'image ici

Pour faire une intégration, Git devra créer un nouveau commit contenant les différences entre eux – la validation de fusion.

entrer la description de l'image ici

Commits humains et fusions Commits

Normalement, un commit est soigneusement créé par un être humain. C’est une unité significative qui n’englobe que les modifications et les annote avec un commentaire.

Un commit de fusion est un peu différent: au lieu d’être créé par un développeur, il est créé automatiquement par Git. Et au lieu d’envelopper un ensemble de modifications connexes, son but est de connecter deux twigs, comme un nœud. Si vous souhaitez comprendre une opération de fusion ultérieurement, vous devez consulter l’historique des deux twigs et le graphe de validation correspondant.

Intégration avec Rebase

Certaines personnes préfèrent se passer de tels commits de fusion automatique. Au lieu de cela, ils veulent que l’histoire du projet ait l’air d’avoir évolué en une seule ligne droite. Rien n’indique qu’il ait été divisé en plusieurs twigs à un moment donné.

entrer la description de l'image ici

Passons en revue une opération de rebase étape par étape. Le scénario est le même que dans les exemples précédents: nous voulons intégrer les modifications de la twig B dans la twig A, mais maintenant, en utilisant la méthode rebase.

entrer la description de l'image ici

Nous allons le faire en trois étapes

  1. git rebase branch-A // syncs the history with branch-A
  2. git checkout branch-A // change the current branch to branch-A
  3. git merge branch-B // merge/take the changes from branch-B to branch-A

Tout d’abord, Git “annulera” tous les commits sur la twig A qui se sont produits après que les lignes ont commencé à se twigr (après la validation commune des ancêtres). Cependant, bien sûr, il ne les rejettera pas: au lieu de cela, vous pouvez penser que ces commits sont “sauvegardés temporairement”.

entrer la description de l'image ici

Ensuite, il applique les commits de la twig-B que nous voulons intégrer. A ce stade, les deux twigs sont identiques.

entrer la description de l'image ici

Dans la dernière étape, les nouveaux commits sur la twig-A sont à présent réappliqués – mais sur une nouvelle position, en plus des validations intégrées de la twig-B (ils sont basés à nouveau). Le résultat ressemble à un développement en ligne droite. Au lieu d’une validation de fusion contenant toutes les modifications combinées, la structure de validation d’origine a été préservée.

entrer la description de l'image ici

Enfin, vous obtenez une twig propre -A sans commits indésirables et générés automatiquement.

Note: Tiré du génial message de git-tower . Les inconvénients de rebase sont également une bonne lecture dans le même post.

Le pro book pro comme une très bonne explication sur la page de rebasage .

Fondamentalement, une fusion prendra 2 commits et les combinera.

A rebase will go to the common ancestor on the 2 and incrementally apply the changes on top of each other. This makes for a ‘cleaner’ and more linear history.

But when you rebase you abandon previous commits and create new ones. So you should never rebase a repo that is public. The other people working on the repo will hate you.

For that reason alone I almost exclusively merge. 99% of the time my twigs don’t differ that much, so if there are conflicts it’s only in one or two places.

This answer is widely oriented around Git Flow . The tables have been generated with the nice ASCII Table Generator , and the history trees with this wonderful command ( aliased as git lg ):

 git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' 

Tables are in reverse chronological order to be more consistent with the history trees. See also the difference between git merge and git merge --no-ff first (you usually want to use git merge --no-ff as it makes your history look closer to the reality):

git merge

Commands:

 Time Branch "develop" Branch "features/foo" ------- ------------------------------ ------------------------------- 15:04 git merge features/foo 15:03 git commit -m "Third commit" 15:02 git commit -m "Second commit" 15:01 git checkout -b features/foo 15:00 git commit -m "First commit" 

Résultat:

 * 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo) | Third commit - Christophe * 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago) | Second commit - Christophe * 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

git merge --no-ff

Commands:

 Time Branch "develop" Branch "features/foo" ------- -------------------------------- ------------------------------- 15:04 git merge --no-ff features/foo 15:03 git commit -m "Third commit" 15:02 git commit -m "Second commit" 15:01 git checkout -b features/foo 15:00 git commit -m "First commit" 

Résultat:

 * 1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop) |\ Merge branch 'features/foo' - Christophe | * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo) | | Third commit - Christophe | * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago) |/ Second commit - Christophe * c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

git merge vs git rebase

First point: always merge features into develop, never rebase develop from features . This is a consequence of the Golden Rule of Rebasing :

The golden rule of git rebase is to never use it on public twigs.

In other words :

Never rebase anything you’ve pushed somewhere.

I would personally add: unless it’s a feature branch AND you and your team are aware of the consequences .

So the question of git merge vs git rebase applies almost only to the feature twigs (in the following examples, --no-ff has always been used when merging). Note that since I’m not sure there’s one better solution ( a debate exists ), I’ll only provide how both commands behave. In my case, I prefer using git rebase as it produces a nicer history tree 🙂

Between feature twigs

git merge

Commands:

 Time Branch "develop" Branch "features/foo" Branch "features/bar" ------- -------------------------------- ------------------------------- -------------------------------- 15:10 git merge --no-ff features/bar 15:09 git merge --no-ff features/foo 15:08 git commit -m "Sixth commit" 15:07 git merge --no-ff features/foo 15:06 git commit -m "Fifth commit" 15:05 git commit -m "Fourth commit" 15:04 git commit -m "Third commit" 15:03 git commit -m "Second commit" 15:02 git checkout -b features/bar 15:01 git checkout -b features/foo 15:00 git commit -m "First commit" 

Résultat:

 * c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop) |\ Merge branch 'features/bar' - Christophe | * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar) | | Sixth commit - Christophe | * eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago) | |\ Merge branch 'features/foo' into features/bar - Christophe | * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago) | | | Fifth commit - Christophe | * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago) | | | Fourth commit - Christophe * | | 98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago) |\ \ \ Merge branch 'features/foo' - Christophe | |/ / |/| / | |/ | * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo) | | Third commit - Christophe | * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago) |/ Second commit - Christophe * 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

git rebase

Commands:

 Time Branch "develop" Branch "features/foo" Branch "features/bar" ------- -------------------------------- ------------------------------- ------------------------------- 15:10 git merge --no-ff features/bar 15:09 git merge --no-ff features/foo 15:08 git commit -m "Sixth commit" 15:07 git rebase features/foo 15:06 git commit -m "Fifth commit" 15:05 git commit -m "Fourth commit" 15:04 git commit -m "Third commit" 15:03 git commit -m "Second commit" 15:02 git checkout -b features/bar 15:01 git checkout -b features/foo 15:00 git commit -m "First commit" 

Résultat:

 * 7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop) |\ Merge branch 'features/bar' - Christophe | * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar) | | Sixth commit - Christophe | * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago) | | Fifth commit - Christophe | * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago) | | Fourth commit - Christophe * | 189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago) |\ \ Merge branch 'features/foo' - Christophe | |/ | * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo) | | Third commit - Christophe | * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago) |/ Second commit - Christophe * ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

From develop to a feature branch

git merge

Commands:

 Time Branch “develop" Branch "features/foo" Branch "features/bar" ------- -------------------------------- ------------------------------- ------------------------------- 15:10 git merge --no-ff features/bar 15:09 git commit -m “Sixth commit" 15:08 git merge --no-ff development 15:07 git merge --no-ff features/foo 15:06 git commit -m “Fifth commit" 15:05 git commit -m “Fourth commit" 15:04 git commit -m “Third commit" 15:03 git commit -m “Second commit" 15:02 git checkout -b features/bar 15:01 git checkout -b features/foo 15:00 git commit -m “First commit" 

Résultat:

 * 9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop) |\ Merge branch 'features/bar' - Christophe | * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar) | | Sixth commit - Christophe | * d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago) | |\ Merge branch 'develop' into features/bar - Christophe | |/ |/| * | 5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago) |\ \ Merge branch 'features/foo' - Christophe | * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo) | | | Third commit - Christophe | * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago) |/ / Second commit - Christophe | * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago) | | Fifth commit - Christophe | * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago) |/ Fourth commit - Christophe * 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

git rebase

Commands:

 Time Branch “develop" Branch "features/foo" Branch "features/bar" ------- -------------------------------- ------------------------------- ------------------------------- 15:10 git merge --no-ff features/bar 15:09 git commit -m “Sixth commit" 15:08 git rebase development 15:07 git merge --no-ff features/foo 15:06 git commit -m “Fifth commit" 15:05 git commit -m “Fourth commit" 15:04 git commit -m “Third commit" 15:03 git commit -m “Second commit" 15:02 git checkout -b features/bar 15:01 git checkout -b features/foo 15:00 git commit -m “First commit" 

Résultat:

 * b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop) |\ Merge branch 'features/bar' - Christophe | * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar) | | Sixth commit - Christophe | * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago) | | Fifth commit - Christophe | * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago) |/ Fourth commit - Christophe * 856433e - YYYY-MM-DD 15:07:00 (XX minutes ago) |\ Merge branch 'features/foo' - Christophe | * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo) | | Third commit - Christophe | * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago) |/ Second commit - Christophe * d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

Side notes

git cherry-pick

When you just need one specific commit, git cherry-pick is a nice solution (the -x option appends a line that says ” (cherry picked from commit…) ” to the original commit message body, so it’s usually a good idea to use it – git log to see it):

Commands:

 Time Branch “develop" Branch "features/foo" Branch "features/bar" ------- -------------------------------- ------------------------------- ----------------------------------------- 15:10 git merge --no-ff features/bar 15:09 git merge --no-ff features/foo 15:08 git commit -m “Sixth commit" 15:07 git cherry-pick -x  15:06 git commit -m “Fifth commit" 15:05 git commit -m “Fourth commit" 15:04 git commit -m “Third commit" 15:03 git commit -m “Second commit" 15:02 git checkout -b features/bar 15:01 git checkout -b features/foo 15:00 git commit -m “First commit" 

Résultat:

 * 50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop) |\ Merge branch 'features/bar' - Christophe | * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar) | | Sixth commit - Christophe | * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago) | | Second commit - Christophe | * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago) | | Fifth commit - Christophe | * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago) | | Fourth commit - Christophe * | 1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago) |\ \ Merge branch 'features/foo' - Christophe | |/ |/| | * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo) | | Third commit - Christophe | * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago) |/ Second commit - Christophe * 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago) First commit - Christophe 

git pull --rebase

Not sure I can explain it better than Derek Gourlay … Basically, use git pull --rebase instead of git pull 🙂 What’s missing in the article though, is that you can enable it by default :

 git config --global pull.rebase true 

git rerere

Again, nicely explained here . But put simple, if you enable it, you won’t have to resolve the same conflict multiple times anymore.

Git rebase is used to make the branching paths in history cleaner and repository structure linear.

It is also used to keep the twigs created by you private, as after rebasing and pushing the changes to server, if you delete your branch, there will be no evidence of branch you have worked upon. So your branch is now your local concern.

After doing rebase we also get rid of an extra commit which we used to see if we do normal merge.

And yes one still needs to do merge after a successful rebase as rebase command just puts your work on top of the branch you mentioned during rebase say master and makes the first commit of your branch as a direct descendant of the master branch. This means we can now do a fast forward merge to bring changes from this branch to master branch.

Some practical examples, somewhat connected to large scale development where gerrit is used for review and delivery integration.

I merge when i uplift my feature branch to a fresh remote master. This gives minimal uplift work and it’s easy to follow the history of the feature development in for example gitk.

 git fetch git checkout origin/my_feature git merge origin/master git commit git push origin HEAD:refs/for/my_feature 

I merge when I prepare a delivery commit.

 git fetch git checkout origin/master git merge --squash origin/my_feature git commit git push origin HEAD:refs/for/master 

I rebase when my delivery commit fails integration for whatever reason and I need to update it towards a fresh remote master.

 git fetch git fetch  git checkout FETCH_HEAD git rebase origin/master git push origin HEAD:refs/for/master 

When do I use git rebase ? Almost never, because it rewrites history. git merge is almost always the preferable choice, because it respects what actually happened in your project.