Quand est-il recommandé d’utiliser git rebase
vs git merge
?
Dois-je encore fusionner après un rebase réussi?
Alors, quand utilisez-vous l’un ou l’autre?
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é
nous obtenons en rebasant:
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:
master
. 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:
En revanche, fusionner une twig de sujet en master:
En cas de doute, utilisez la fusion.
Les seules différences entre une rebase et une fusion sont les suivantes:
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 .
Il y a quelques facteurs à considérer lors du choix de l’opération à utiliser.
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.
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.
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.
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.
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).
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.
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.
Si vous souhaitez alias rm
to rm -rf
pour “gagner du temps”, alors rebase est peut-être pour vous.
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.
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:
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.
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.
Dans beaucoup de cas, cependant, les deux twigs ont progressé individuellement.
Pour faire une intégration, Git devra créer un nouveau commit contenant les différences entre eux – la validation de fusion.
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é.
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.
Nous allons le faire en trois étapes
git rebase branch-A // syncs the history with branch-A
git checkout branch-A // change the current branch to branch-A
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”.
Ensuite, il applique les commits de la twig-B que nous voulons intégrer. A ce stade, les deux twigs sont identiques.
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.
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 🙂
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
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
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.