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


Quand est-il recommandé d'utiliser git rebase contre. git merge?

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


1246
2018-04-29 20:26


origine


Réponses:


Version courte

  • Fusionner prend tous les changements dans une branche et les fusionne dans une autre branche dans un commit.
  • Rebase dit que je veux le point où je me suis ramifié pour passer à un nouveau point de départ

Alors quand utilisez-vous l'un ou l'autre?

Fusionner

  • Disons que vous avez créé une branche dans le but de développer une fonctionnalité unique. Quand vous voulez ramener ces changements au master, vous voulez probablement fusionner (vous ne vous souciez pas de maintenir tous les commits intermédiaires).

Rebase

  • Un deuxième scénario serait si vous avez commencé à faire du développement et qu'un autre développeur a fait un changement sans rapport. Vous voulez probablement tirer, puis rebaser pour baser vos modifications de la version actuelle du repo.

973
2018-04-29 20:38



C'est simple, avec rebase vous dites d'utiliser une autre branche comme la nouvelle base pour ton travail.

Si vous avez par exemple une succursale master et vous créez une branche pour implémenter une nouvelle fonctionnalité, disons que vous l'appelez cool-feature, bien sûr, la branche master est la base de votre nouvelle fonctionnalité.

Maintenant, à un certain moment, vous voulez ajouter la nouvelle fonctionnalité que vous avez implémentée dans le master branche. Vous pouvez simplement passer à master et fusionner le cool-feature branche:

$git checkout master
$git merge cool-feature

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

$git checkout cool-feature
$git rebase master

puis fusionner dans master:

$git checkout master
$git merge cool-feature

Cette fois, puisque la branche de sujet a les mêmes commits de maître plus les commits avec la nouvelle fonctionnalité, la fusion sera juste une avance rapide.


288
2018-02-05 06:28



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

  • un rebase est souvent une bonne idée à faire avant une fusion, parce que l'idée est que vous intégrez dans votre branche Y le travail de la branche B sur lequel vous allez fusionner.
    Mais encore une fois, avant de fusionner, vous résolvez tout conflit dans votre branche (c'est-à-dire: "rebase", comme dans "rejouer mon travail dans ma branche à partir d'un point récent de la branche B)
    Si c'est fait correctement, la fusion subséquente de votre branche à la branche B peut être rapide.

  • un impact de fusion directement la branche de destination B, ce qui signifie que les fusions doivent être triviales, sinon cette branche B peut être long pour revenir à un état stable (le temps pour vous de résoudre tous les conflits)


le point de fusion après un rebase?

Dans le cas que je décris, je rebase B sur ma branche, juste pour avoir l'occasion de rejouer mon travail d'un point plus récent de B, mais en restant dans ma branche.
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), est d'apporter votre travail directement dans B grâce à un rebase (qui conserve tous vos bons commits, ou même vous donne l'opportunité de les ré-ordonner via un rebase interactif).
Dans ce cas (où vous rebasez en étant dans la branche B), vous avez raison: aucune fusion supplémentaire n'est nécessaire:

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

rebase1 

nous obtenons en rebasant:

rebase3

Ce deuxième scénario est tout: comment puis-je obtenir de nouvelles fonctionnalités dans le maître.

Mon point, en décrivant le premier scénario de rebasage, est de rappeler à tout le monde qu'un rebase peut aussi être utilisé comme une étape préliminaire à cela (c'est-à-dire «ramener une nouvelle fonctionnalité dans le maître»).
Vous pouvez utiliser rebase pour amener le maître "in" dans la nouvelle branche: le rebase relit les nouveaux HEAD master, mais toujours dans la branche new-feature, en déplaçant efficacement votre point de départ de la branche d'un ancien maître à HEAD-master.
Cela vous permet de résoudre tous les conflits dans votre branche (ce qui signifie, isolément, tout en permettant au maître de continuer à évoluer en parallèle si l'étape de résolution de conflit prend trop de temps).
Ensuite, vous pouvez passer à maître et fusionner new-feature (ou rebase new-feature sur master si vous voulez préserver les commits faits dans votre new-feature branche).

Alors:

  • "rebase vs fusion" peut être vu comme deux façons d'importer un travail, disons, master.
  • Mais "rebaser then merge" peut être un workflow valide pour résoudre d'abord un conflit de manière isolée, puis ramener votre travail.

253
2018-04-29 20:44



Beaucoup de réponses disent que la fusion transforme tous vos commits en un, et suggère donc d'utiliser rebase pour préserver vos commits. Ceci est une erreur. Et une mauvaise idée si vous avez déjà poussé vos commits.

Fusionner ne pas oblitérer vos commits. Fusionner préserve l'histoire! (il suffit de regarder gitk) Rebase réécrit l'histoire, ce qui est une mauvaise chose après que vous avez poussé il.

Utiliser la fusion - ne pas rebaser chaque fois que vous avez déjà poussé.

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

Rebaser une branche sur le maître:

  • fournit une idée incorrecte de la façon dont les commits ont été créés
  • pollue le maître avec un tas de commits intermédiaires qui n'ont peut-être pas été bien testés
  • pourrait réellement introduire des sauts de construction sur ces commits intermédiaires en raison des changements qui ont été faits pour maîtriser entre quand la branche originale de sujet a été créée et quand elle a été rebasée.
  • fait de trouver de bons endroits dans le maître à la caisse difficile.
  • Provoque l'horodatage des validations pour ne pas s'aligner sur leur ordre chronologique dans l'arborescence. Ainsi, vous verriez que commit A précède la validation B dans master, mais que commit B a été créé en premier. (Quelle?!)
  • Génère plus de conflits car les commits individuels dans la branche sujet peuvent chacun impliquer des conflits de fusion qui doivent être résolus individuellement (mentir davantage dans l'histoire sur ce qui s'est passé dans chaque commit).
  • est une réécriture de l'histoire. Si la branche rebasée a été poussée n'importe où (partagée avec quelqu'un d'autre que vous-même), alors vous avez foiré tout le monde qui a cette branche depuis que vous avez réécrit l'histoire.

En revanche, fusionner une branche de sujet en master:

  • préserve l'historique de la création des branches de rubrique, y compris les fusions de la branche principale vers la branche de rubrique afin de la maintenir à jour. Vous avez vraiment une idée précise du code avec lequel le développeur travaillait lors de la construction.
  • master est une branche constituée principalement de fusions, et chacun de ces commits de fusion est typiquement un «bon point» dans l'histoire qui est sûr à vérifier parce que c'est là que la branche de sujet était prête à être intégrée.
  • tous les commits individuels de la branche de sujet sont conservés, y compris le fait qu'ils étaient dans une branche de sujet, donc isoler ces changements est naturel et vous pouvez forer dedans si nécessaire.
  • les conflits de fusion ne doivent être résolus qu'une seule fois (au moment de la fusion), de sorte que les modifications de validation intermédiaires effectuées dans la branche de sujet ne doivent pas être résolues indépendamment.
  • peut être fait plusieurs fois en douceur. Si vous intégrez périodiquement votre branche thématique à la base de données, les personnes peuvent continuer à s'appuyer sur la branche thématique et continuer à fusionner de manière indépendante.

151
2018-02-03 22:17



TL; DR

Si vous avez un doute, utilisez la fusion.

Réponse courte

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

  • La structure arborescente résultante de l'historique (généralement visible uniquement lorsque l'on regarde un graphique de validation) est différente (l'une aura des branches, l'autre ne le fera pas).
  • La fusion crée généralement un commit supplémentaire (par exemple, un noeud dans l'arborescence).
  • Fusionner et rebaser gérera les conflits différemment. Rebase présentera des conflits que l'on commettra à la fois où la fusion les présentera tous en même temps.

Donc, la réponse courte est de choisissez rebaser ou fusionner en fonction de ce que vous voulez que votre histoire ressemble.

Longue réponse

Vous devez prendre en compte certains facteurs lors du choix de l'opération à utiliser.

Est-ce que la branche dont vous faites part des modifications est partagée avec d'autres développeurs extérieurs à votre équipe (par exemple open source, public)?

Si oui, ne pas rebaser. Rebase détruit la branche et ces développeurs auront des dépôts cassés / incohérents à moins qu'ils n'utilisent git pull --rebase. C'est un bon moyen de déranger 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 pourriez perdre du travail engagé et / ou casser la cohérence des dépôts d'autres développeurs.

J'ai travaillé sur des équipes où les développeurs venaient tous d'une époque où les entreprises pouvaient se permettre d'avoir du personnel dédié pour s'occuper de l'embranchement et de la fusion. Ces développeurs ne connaissent pas grand chose de Git et ne veulent pas en savoir beaucoup. Dans ces équipes, je ne risquerais pas de recommander le rebasage pour une raison quelconque.

La branche elle-même représente-t-elle des informations utiles

Certaines équipes utilisent le modèle de branche par entité, dans lequel chaque branche représente une entité (ou une correction de bogue, ou une sous-fonctionnalité, etc.). Dans ce modèle, la branche aide à identifier les ensembles de commits associés. Par exemple, on peut rapidement inverser une fonction en inversant la fusion de cette branche (pour être juste, c'est une opération rare). Ou diff une fonctionnalité en comparant deux branches (plus commun). Rebase détruirait la branche et ce ne serait pas simple.

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

Pourriez-vous revenir à la fusion pour une raison quelconque?

Rétablir (comme dans l'annulation) un rebasage est considérablement difficile et / ou impossible (si le rebasage a eu des conflits) par rapport à la restauration d'une fusion. Si vous pensez qu'il y a une chance que vous souhaitiez revenir, utilisez la fusion.

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

Les opérations de rebasage doivent être tirées avec un git pull --rebase. Si vous travaillez par vous-même, vous pouvez vous souvenir de ce que vous devriez utiliser au moment opportun. Si vous travaillez en équipe, cela sera très difficile à coordonner. C'est pourquoi la plupart des workflows de rebasage recommandent d'utiliser rebase pour toutes les fusions (et git pull --rebase pour tous les tire).

Mythes communs

Fusionner détruit l'histoire (les virgules sont validées)

En supposant que vous avez la fusion suivante:

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

Certaines personnes diront que la fusion "détruit" l'historique de commit parce que si vous deviez regarder le journal de la branche principale seulement (A - D) vous manqueriez les messages de validation importants contenus dans B et C.

Si cela était vrai, nous n'aurions pas des questions comme celle-ci. Fondamentalement, vous verrez B et C sauf si vous demandez explicitement de ne pas les voir (en utilisant --first-parent). C'est très facile à 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 certain que l'une soit toujours meilleure que l'autre et cela peut dépendre du flux de travail du développeur. Par exemple, si un développeur a tendance à s'engager régulièrement (par exemple, peut-être qu'ils s'engagent deux fois par jour lors de la transition du travail à la maison), il peut y avoir beaucoup de commits pour une branche donnée. Beaucoup de ces commits pourraient ne ressembler en rien au produit final (j'ai tendance à refactoriser mon approche une ou deux fois par caractéristique). Si quelqu'un d'autre travaillait sur un domaine de code connexe et essayait de rebaser mes modifications, cela pourrait être une opération assez fastidieuse.

Rebase est plus cool / sexy / plus professionnel

Si vous aimez alias rm à rm -rf pour "gagner du temps" alors peut-être que le rebasage est pour vous.

Mes deux centimes

Je pense toujours qu'un jour je tomberai sur 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ù git reflog est un outil génial qui résout mon problème. J'ai travaillé avec git pendant plus de cinq ans maintenant. Cela n'est pas arrivé.

Les histoires désordonnées n'ont jamais vraiment été un problème pour moi. Je ne lis jamais mon histoire de commit comme un roman passionnant. Une majorité du temps j'ai besoin d'une histoire que je vais utiliser git blame ou git bisect de toute façon. Dans ce cas, avoir la validation de fusion est réellement utile pour moi parce que si la fusion a introduit le problème qui est une information significative pour moi.

Mise à jour (4/2017)

Je me sens obligé de mentionner que j'ai personnellement adouci sur l'utilisation de rebase, bien que mon conseil général reste valable. J'ai récemment beaucoup interagit avec le Angulaire 2 Matériel projet. Ils ont utilisé rebase pour garder un historique de commit très propre. Cela m'a permis de voir très facilement ce que commit corrigeait un défaut donné et si ce commit était inclus ou non dans une release. C'est un bon exemple d'utilisation de rebase correctement.


114
2018-04-13 02:16



Fusionner signifie: créer un seul nouveau commit qui fusionne mes modifications dans la destination.

Rebase signifie: Créer une nouvelle série de commits, en utilisant mon ensemble actuel de commits comme indices. En d'autres termes, calculez ce que mes changements auraient ressemblé si j'avais commencé à les faire à partir du point sur lequel je suis en train de rebasculer. Après le rebasage, vous devrez peut-être tester à nouveau vos modifications et pendant le rebasage, vous aurez peut-être quelques conflits.

Compte tenu de cela, pourquoi voudriez-vous rebaser? Juste pour garder l'histoire du développement clair. Imaginons que vous travailliez sur la fonctionnalité X et lorsque vous avez terminé, vous fusionnez vos modifications. La destination aura désormais un seul commit qui dirait quelque chose comme "Fonctionnalité ajoutée X". Maintenant, au lieu de fusionner, si vous avez rebasé puis fusionné, l'historique de développement de destination contiendrait tous les commits individuels dans une seule progression logique. Cela rend la révision des changements plus facile beaucoup plus tard. Imaginez à quel point vous auriez du mal à revoir l'historique de développement si 50 développeurs fusionnaient constamment différentes fonctionnalités.

Cela dit, si vous avez déjà poussé la branche sur laquelle vous travaillez en amont, vous ne devriez pas rebaser, mais fusionner à la place. Pour les branches qui n'ont pas été poussées en amont, rebaser, tester et fusionner.

Une autre fois, vous pourriez vouloir rebaser, c'est quand vous voulez vous débarrasser des commits de votre branche avant de pousser en amont. Par exemple: Commits qui introduisent un code de débogage au début et d'autres s'engage plus loin sur ce nettoyage de ce code. La seule façon de le faire est d'effectuer une rebase interactive: git rebase -i <branch/commit/tag>

UPDATE: Vous voulez également utiliser rebase lorsque vous utilisez Git pour vous interfacer avec un système de contrôle de version qui ne supporte pas l'historique non linéaire (subversion par exemple). Lors de l'utilisation du pont git-svn, il est très important que les modifications que vous fusionnez dans subversion soient une liste séquentielle de changements en plus des changements les plus récents dans le tronc. Il n'y a que deux façons de le faire: (1) Recréer manuellement les changements et (2) Utiliser la commande rebase, ce qui est beaucoup plus rapide.

UPDATE2: Une autre façon de penser à un rebasage 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 commettre en petits morceaux minuscules. Vous avez un engagement à corriger une faute de frappe, un engagement à se débarrasser du code inutilisé et ainsi de suite. 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 que vous vous engagez encourage les grands commits, donc pour le travail que vous faites, on s'attendrait à un ou peut-être deux commits. Comment prenez-vous votre chaîne de commits et les compresser à ce qui est attendu? Vous utiliseriez un rebasage interactif et écraseriez vos minuscules commits en plus petits morceaux. La même chose est vraie si l'inverse était nécessaire - si votre style était quelques grands commits, mais le repo a exigé de longues chaînes de petits commits. Vous utiliseriez un rebase pour faire cela aussi. Si vous aviez fusionné à la place, vous avez maintenant greffé votre style de commit sur le dépôt 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 commit différents après un certain temps.

UPDATE3: Does one still need to merge after a successful rebase? Oui, vous faites. La raison en est qu'un rebasage implique essentiellement un "déplacement" des commits. Comme je l'ai dit plus haut, ces commits sont calculés, mais si vous aviez 14 commits à partir du branchement, alors en supposant que rien ne se passe mal avec votre rebase, vous serez 14 commits en avance (du point où vous rebasez) après la rebase est terminée. Vous aviez une branche avant un rebase. Vous aurez une branche de la même longueur après. Vous devez toujours fusionner avant de publier vos modifications. En d'autres termes, rebasez autant de fois que vous le souhaitez (à nouveau, uniquement si vous n'avez pas poussé vos modifications en amont). Fusionner seulement après avoir rebasé.


65
2018-02-05 06:47



avant de fusionner / rebaser:

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 bien d'autres informations bien illustrées sur git peuvent être trouvées ici: http://excess.org/article/2008/07/ogre-git-tutorial/


54
2018-06-07 06:19



Cette phrase l'obtient:

En général, la façon de tirer le meilleur parti des deux mondes consiste à   les changements que vous avez faits, mais n'ont pas encore partagé avant de les pousser dans   afin de nettoyer votre histoire, mais ne jamais rebaser tout ce que vous avez poussé   quelque part.

La source: http://www.git-scm.com/book/fr/v2/Git-Branching-Rebasing#Rebase-vs.-Merge


25
2018-01-05 13:50



Bien que la fusion soit certainement la façon la plus simple et la plus courante d'intégrer les changements, ce n'est pas la seule: Rebase est un moyen alternatif d'intégration.

Comprendre Fusionner un peu mieux

Lorsque Git effectue une fusion, il recherche trois validations:

  • (1) Common ancestor commit Si vous suivez l'historique de deux branches dans un projet, elles ont toujours au moins un commit en commun: à ce moment, les deux branches ont le même contenu et évoluent ensuite différemment.
  • (2) + (3) Endpoints de chaque branche Le but d'une intégration est de combiner les états actuels de deux branches. Par conséquent, leurs dernières révisions respectives présentent un intérêt particulier. La combinaison de ces trois engagements aboutira à l'intégration que nous visons.

Avance rapide ou fusionner la validation

Dans des cas très simples, l'une des deux branches n'a aucun nouveau commit depuis que la branche s'est produite - son dernier commit est toujours l'ancêtre commun.

enter image description here

Dans ce cas, effectuer l'intégration est simple: Git peut simplement ajouter toutes les validations de l'autre branche en plus de la validation de l'ancêtre commun. Dans Git, cette forme d'intégration la plus simple s'appelle une fusion "fast-forward". Les deux branches partagent alors exactement la même histoire.

enter image description here

Dans beaucoup de cas, cependant, les deux branches ont progressé individuellement. enter image description here

Pour faire une intégration, Git devra créer un nouveau commit qui contiendra les différences entre eux - le commit de fusion.

enter image description here

Commissions humaines et fusion des commits

Normalement, un commit est soigneusement créé par un être humain. C'est une unité significative qui enveloppe seulement les changements liés 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 changements liés, son but est de relier deux branches, juste comme un noeud. Si vous voulez comprendre une opération de fusion plus tard, vous devez jeter un coup d'œil à l'historique des deux branches et au graphique 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 branches à un moment donné.

enter image description here

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

enter image description here

Nous ferons cela 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" toutes les validations sur la branche A qui se sont produites après le début de la dérivation des lignes (après la validation de l'ancêtre commun). Cependant, bien sûr, il ne les rejettera pas: à la place, vous pouvez considérer ces commits comme étant "sauvés temporairement".

enter image description here

Ensuite, il applique les commits de la branche B que nous voulons intégrer. À ce stade, les deux branches se ressemblent exactement.

enter image description here

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

enter image description here

Enfin, vous obtenez une branche propre branche-A sans commits non désirés et générés automatiquement.

Remarque: Tiré de l'impressionnant poster par git-tower. le désavantages de rebase est aussi une bonne lecture dans le même post.


23
2017-10-12 11:52



Le livre pro git comme une très bonne explication sur le page de rebasage.

Fondamentalement, une fusion prendra 2 commits et les combiner.

Une rebase ira à l'ancêtre commun sur le 2 et appliquera progressivement les changements les uns sur les autres. Cela rend l'histoire plus «propre» et plus linéaire.

Mais quand vous rebassez, vous abandonnez les commits précédents et en créez de nouveaux. Vous ne devriez donc jamais rebaser un dépôt public. Les autres personnes travaillant sur le repo vous détesteront.

Pour cette seule raison, je fusionne presque exclusivement. 99% du temps mes branches ne diffèrent pas beaucoup, donc s'il y a des conflits c'est seulement dans un ou deux endroits.


15
2017-12-20 21:41



Cette réponse est largement orientée autour Git Flow. Les tables ont été générées avec le gentil Générateur de table ASCII, et les arbres d'histoire avec cette merveilleuse commande (aliasé comme 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)'

Les tableaux sont dans l'ordre chronologique inverse pour être plus cohérent avec les arbres d'histoire. Voir aussi la différence entre git merge et git merge --no-ff d'abord (vous voulez généralement utiliser git merge --no-ff car cela rend votre histoire plus proche de la réalité):

git merge

Commandes

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

Commandes

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 contre git rebase

Premier point: toujours fusionner les fonctionnalités en développement, ne jamais rebaser développer à partir de fonctionnalités. Ceci est une conséquence de Règle d'or de Rebasing:

La règle d'or de git rebase est de ne jamais l'utiliser sur Publiquebranches.

En d'autres termes:

Ne jamais rebaser quelque chose que vous avez poussé quelque part.

J'ajouterais personnellement: sauf si c'est une branche de fonctionnalité ET vous et votre équipe sont conscients des conséquences.

Donc la question de git merge contre git rebase s'applique presque uniquement aux branches d'entités (dans les exemples suivants, --no-ff a toujours été utilisé lors de la fusion). Notez que puisque je ne suis pas sûr qu'il y a une meilleure solution (un débat existe), Je vais seulement indiquer comment les deux commandes se comportent. Dans mon cas, je préfère utiliser git rebase car il produit un arbre d'histoire plus agréable :)

Entre les branches de fonctionnalité

git merge

Commandes

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

Commandes

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

De develop à une branche de fonctionnalité

git merge

Commandes

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

Commandes

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

Notes secondaires

git cherry-pick

Lorsque vous avez juste besoin d'un commit spécifique, git cherry-pick est une bonne solution (la -x option ajoute une ligne qui dit "(cerise ramassé de commettre ...)"au corps du message de commit original, c'est donc une bonne idée de l'utiliser - git log <commit_sha1> voir ça):

Commandes

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 <second_commit_sha1>  
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

Je ne suis pas sûr de pouvoir l'expliquer mieux que Derek Gourlay... Fondamentalement, utilisez git pull --rebase au lieu de git pull :) Ce qui manque dans l'article, c'est que vous pouvez l'activer par défaut:

git config --global pull.rebase true

git rerere

Encore une fois, bien expliqué ici. Mais mis simple, si vous l'activez, vous n'aurez plus à résoudre le même conflit plusieurs fois.


14
2018-02-10 17:26