Quand est-il recommandé d'utiliser git rebase
contre git merge
?
Dois-je quand même fusionner après un rebasement réussi?
Alors, quand utilisez-vous l'un ou l'autre?
C'est simple, avec rebase, vous dites d'utiliser une autre branche comme nouvelle base pour votre travail.
Si vous avez par exemple une branche master
et que vous créez une branche pour implémenter une nouvelle fonctionnalité, dites-lui que vous l'appelez cool-feature
, bien entendu, la branche principale constitue la base de votre nouvelle fonctionnalité.
Désormais, vous souhaitez ajouter la nouvelle fonctionnalité que vous avez implémentée dans la branche master
. Vous pouvez simplement passer à master
et fusionner la branche cool-feature
:
$ git checkout master
$ git merge cool-feature
mais de cette façon, un nouveau commit factice est ajouté. Si vous voulez éviter les spaghettis, vous pouvez rebase:
$ git checkout cool-feature
$ git rebase master
puis fusionnez-le dans master
:
$ git checkout master
$ git merge cool-feature
Cette fois, étant donné que la branche de sujet a les mêmes commits de maître ainsi que les commits avec la nouvelle fonctionnalité, la fusion sera simplement une avance rapide.
Pour compléter ma propre réponse mentionnée par TSamper ,
une refonte est souvent une bonne idée à faire avant une fusion, car l’idée est d’intégrer 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 la branche {votre} (c'est-à-dire: "rebase", comme dans "rejouer mon travail dans ma branche à partir d'un point récent de la branche B
)
Si cela est fait correctement, la fusion suivante de votre branche en branche B
peut être effectuée rapidement.
un impact de fusion directement sur la branche de destination B
, ce qui signifie que les fusions doivent être simples, sinon cette branche B
peut être longue pour revenir à un état stable (il est temps de résoudre tous les conflits)
le point de fusion après une rebase?
Dans le cas que je décris, je rebase B
sur ma branche, uniquement pour pouvoir rejouer mon travail à partir d'un point plus récent de B
, mais tout en restant dans ma branche.
Dans ce cas, une fusion est encore nécessaire pour que mon travail "rejoué" sur B
.
L’autre scénario ( décrit dans Git Ready par exemple) consiste à importer votre travail directement dans B
par le biais d’une base (ce qui permet de conserver tous vos commits Nice ou même de vous permettre de les commander à nouveau via une commande interactive. rebase).
Dans ce cas (vous vous rebassez tout en étant dans la branche B), vous avez raison: aucune autre fusion n'est nécessaire:
Un arbre git par défaut quand on n'a pas fusionné ni rebasé
nous obtenons en rebasant:
Ce deuxième scénario est tout au sujet de: comment puis-je obtenir de nouvelles fonctionnalités dans Master.
Mon but, en décrivant le premier scénario de rebase, est de rappeler à tout le monde qu’un rebase peut également être utilisé comme étape préliminaire à cela (c’est-à-dire "ramener la nouvelle fonctionnalité dans le maître").
Vous pouvez utiliser rebase pour amener d'abord le maître "dans" la nouvelle branche: la nouvelle base relit les commits de nouvelle fonctionnalité à partir du HEAD master
, mais toujours dans la nouvelle branche, ce qui déplace effectivement le point de départ de votre branche d'un ancien master commit to HEAD-master
.
Cela vous permet de résoudre tout conflit dans votre branche (ce qui signifie, isolément, tout en permettant à maître de continuer à évoluer en parallèle si l'étape de résolution du conflit prend trop de temps).
Ensuite, vous pouvez passer à master et fusionner new-feature
(ou redéfinir new-feature
sur master
si vous souhaitez conserver les validations effectuées dans votre branche new-feature
).
Alors:
master
. Beaucoup de réponses ici disent que la fusion transforme tous vos commits en un, et suggèrent 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.
La fusion fait pas effacer 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 l’ayez poussée.
Use merge - ne rebase pas chaque fois que vous avez déjà poussé.
Voici Linus (auteur de git) prend sur elle . C'est une très bonne lecture. Ou vous pouvez lire ma propre version de la même idée ci-dessous.
Redéfinition d’une branche sur master:
En revanche, fusionner une branche de sujet en maître:
Si vous avez un doute, utilisez la fusion.
Les seules différences entre une base et une fusion sont les suivantes:
La réponse courte est donc de choisir une base ou une fusion en fonction de ce que vous voulez que votre historique ressemble à.
Il y a quelques facteurs à prendre en compte lors du choix de l'opération à utiliser.
Si c'est le cas, ne rebase pas. Rebase détruit la branche et ces développeurs auront des référentiels endommagés/incohérents à moins qu’ils utilisent 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 un travail validé et/ou de casser la cohérence des référentiels d'autres développeurs. _
J'ai travaillé au sein d'équipes où les développeurs venaient tous d'une époque où les entreprises pouvaient se permettre un personnel dédié pour gérer les branches et les fusions. Ces développeurs ne connaissent pas beaucoup Git et ne veulent pas en savoir plus. Dans ces équipes, je ne risquerais pas de recommander un changement de base pour une raison quelconque.
Certaines équipes utilisent le modèle branche par entité, chaque branche représentant une fonctionnalité (ou une correction de bogue, ou une sous-fonctionnalité, etc.). Dans ce modèle, la branche aide à identifier des ensembles de validations associées. Par exemple, on peut rapidement revenir sur une fonctionnalité en annulant la fusion de cette branche (pour être honnête, il s'agit d'une opération rare). Ou diff une fonctionnalité en comparant deux branches (plus communes). Rebase détruirait la branche et ce ne serait pas simple.
J'ai également travaillé sur des équipes utilisant le modèle branche par développeur (nous sommes tous passés par là). Dans ce cas, la branche elle-même ne transmet aucune information supplémentaire (la validation a déjà l'auteur). Il n'y aurait pas de mal à rebaser.
L'annulation (comme l'annulation) d'une base est considérablement difficile et/ou impossible (si la base a des conflits) par rapport à l'annulation d'une fusion. Si vous pensez qu'il est possible que vous souhaitiez revenir en arrière, utilisez la fusion.
Les opérations de base doivent être extraites avec un git pull --rebase
correspondant. Si vous travaillez seul, vous pourrez peut-être vous rappeler lequel vous devriez utiliser au moment opportun. Si vous travaillez en équipe, ce sera très difficile à coordonner. C'est la raison pour laquelle la plupart des flux de travaux de refonte recommandent d'utiliser rebase pour toutes les fusions (et git pull --rebase
pour toutes les analyses).
En supposant que vous ayez la fusion suivante:
B -- C
/ \
A--------D
Certaines personnes diront que la fusion "détruit" l'historique de validation, car si vous ne consultiez que le journal de la branche principale (A - D), vous perdriez les messages de validation importants contenus dans B et C.
Si cela était vrai, nous n'aurions pas des questions comme celle-ci . En gros, vous verrez B et C sauf si vous demandez explicitement de ne pas les voir (en utilisant --first-parent). C'est très facile d'essayer vous-même.
Les deux approches fusionnent différemment, mais il n'est pas évident 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’il s’engage deux fois par jour lorsqu’il passe du travail au domicile), il peut y avoir beaucoup d’engagements pour une branche donnée. Beaucoup de ces commits pourraient 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 tentait de modifier ses modifications, l'opération pourrait s'avérer fastidieuse.
Si vous aimez alias rm
to rm -rf
pour "gagner du temps", alors peut-être que rebase est fait pour vous.
Je pense toujours qu'un jour je rencontrerai un scénario dans lequel git Rebase est l'outil génial qui résout le problème. Un peu comme je pense que je vais rencontrer un scénario où git reflog est un outil génial qui résout mon problème. Je travaille avec Git depuis plus de cinq ans maintenant. Cela n'est pas arrivé.
Les histoires désordonnées n'ont jamais été un problème pour moi. Je ne lis jamais mon histoire de commit comme un roman passionnant. La plupart du temps, j'ai besoin d'une histoire, je vais de toute façon utiliser le blâme git ou le couperet. Dans ce cas, la validation de fusion m’est utile, car si la fusion introduit le problème, c’est une information significative pour moi.Mise à jour (4/2017).
I feel obligated to mention that I have personally softened on using rebase although my general advice still stands. I have recently been interacting a lot with the Angular 2 Material project. They have used rebase to keep a very clean commit history. This has allowed me to very easily see what commit fixed a given defect and whether or not that commit was included in a release. It serves as a great example of using rebase correctly.
Fusionner signifie: créer un nouveau commit qui fusionne mes modifications dans la destination.
Rebase signifie: Créez une nouvelle série de commits, en utilisant mes ensembles de commits actuels comme indications. En d’autres termes, calculez à quoi mes modifications auraient ressemblé si j’avais commencé à les modifier à partir du point sur lequel je me basais. Après la création de la base, vous devrez peut-être tester à nouveau vos modifications et, au cours de la création de la base, vous aurez éventuellement quelques conflits.
Compte tenu de cela, pourquoi voudriez-vous rebaser? Juste pour garder l'historique du développement clair. Supposons que vous travaillez sur la fonctionnalité X et que, lorsque vous avez terminé, vous fusionnez vos modifications. La destination comportera désormais un seul commit qui indiquerait quelque chose du type "Ajoutée fonctionnalité X". Désormais, au lieu de fusionner, si vous refaites puis fusionniez, l'historique de développement de la destination contiendrait tous les commits individuels dans une progression logique unique. Cela facilite la révision ultérieure des modifications. Imaginez à quel point il vous serait difficile de passer en revue l’historique du développement si 50 développeurs fusionnaient différentes fonctionnalités à tout moment.
Cela dit, si vous avez déjà poussé la branche sur laquelle vous travaillez en amont, vous ne devez pas rebaser mais plutôt fusionner. Pour les branches qui n'ont pas été poussées en amont, rebassez, testez et fusionnez.
Une autre fois que vous voudrez peut-être rebaser, c'est quand vous voulez vous débarrasser des commits de votre branche avant de pousser en amont. Par exemple: Les validations qui introduisent du code de débogage à un stade précoce et les autres validations qui nettoient ce code. La seule façon de faire est d’effectuer une rebase interactive: git rebase -i <branch/commit/tag>
UPDATE: Vous souhaitez également utiliser rebase lorsque vous utilisez Git pour vous connecter à 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 constituent une liste séquentielle des modifications apportées en plus des modifications les plus récentes apportées au tronc. Il n'y a que deux façons de le faire: (1) recréer manuellement les modifications et (2) utiliser la commande rebase, ce qui est beaucoup plus rapide.
UPDATE2: Une autre façon de penser à une base est de permettre une sorte de correspondance entre votre style de développement et le style accepté dans le référentiel auquel vous vous engagez. Disons que vous aimez vous engager par petits morceaux. Vous avez un engagement pour corriger une faute de frappe, un engagement pour supprimer le code inutilisé, etc. Lorsque vous avez terminé ce que vous devez faire, vous avez une longue série de commits. Supposons maintenant que le référentiel auquel vous vous engagez encourage les gros commits. Par conséquent, pour le travail que vous faites, on pourrait s’attendre à un ou peut-être deux commits. Comment prenez-vous votre chaîne de commits et les compressez-vous à ce qui est attendu? Vous utiliseriez une base interactive et réduiriez vos petits commits en moins de gros morceaux. La même chose est vraie si l'inverse était nécessaire - si votre style était composé de quelques grands commits, mais que le repo exigeait de longues chaînes de petits commits. Vous utiliseriez également un rebase pour le faire. Si vous aviez fusionné à la place, 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 combien il serait difficile de suivre une histoire avec plusieurs styles de commit différents après un certain temps.
UPDATE3: Does one still need to merge after a successful rebase?
Oui, c'est votre cas. La raison est qu'un rebase implique essentiellement un "déplacement" des commits. Comme je l’ai dit plus haut, ces commits sont calculés, mais si vous avez 14 commissions à partir du point de ramification, en supposant que rien ne se passe mal avec votre base, vous aurez 14 commissions devant (du point sur lequel vous vous refaites) après la rebase est faite. Vous avez eu une branche avant un rebase. Vous aurez ensuite une branche de même longueur. Vous devez encore fusionner avant de publier vos modifications. En d'autres termes, rebassez autant de fois que vous le souhaitez (à nouveau, uniquement si vous n'avez pas poussé vos modifications en amont). Fusionner uniquement après avoir rebasé.
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 se trouvent ici: http://excess.org/article/2008/07/ogre-git-tutorial/
Bien que la fusion soit le moyen le plus simple et le plus courant d’intégrer les changements, ce n’est pas le seul: Rebase est un moyen alternatif d’intégration.
Comprendre un peu mieux fusionner
Lorsque Git effectue une fusion, il recherche trois commits:
Validation rapide ou fusion
Dans des cas très simples, l'une des deux branches n'a pas de nouveau commit depuis la création de la branche. Son dernier commit est toujours l'ancêtre commun.
Dans ce cas, effectuer l'intégration est extrêmement simple: Git peut simplement ajouter tous les commits de l'autre branche au-dessus du commit 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.
Cependant, dans de nombreux cas, les deux branches ont progressé individuellement .
Pour effectuer une intégration, Git devra créer un nouveau commit contenant les différences entre eux - le commit de fusion.
Human Commits & Merge Commits
Normalement, un commit est soigneusement créé par un être humain. C'est une unité significative qui résume uniquement les modifications associées 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 objectif est de connecter deux branches, comme un nœud. Si vous souhaitez comprendre une opération de fusion ultérieurement, vous devez consulter l'historique des deux branches et le graphe de validation correspondant.
Intégration avec Rebase
_ {Certaines personnes préfèrent se passer de telles commandes de fusion automatiques. Au lieu de cela, elles souhaitent que l'historique du projet semble avoir évolué en une seule ligne droite.quelque point.
Passons en revue étape par étape une opération de rebase. Le scénario est le même que dans les exemples précédents: nous souhaitons intégrer les modifications de branche B à branche A, mais maintenant en utilisant 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 branche A qui se sont produits après que les lignes aient commencé à se ramifier (après la validation de l'ancêtre commun). Cependant, bien sûr, il ne les écartera pas: vous pouvez plutôt penser à ces commits comme étant "sauvés temporairement".
Ensuite, il applique les commits de la branche B que nous souhaitons intégrer. À ce stade, les deux branches ont exactement la même apparence.
Dans la dernière étape, les nouveaux commits sur la branche A sont maintenant réappliqués - mais sur un nouveau poste, en plus des commits intégrés de la branche B (ils sont ré-basés) .Le résultat ressemble à un développement était arrivé 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 branche propre branch-A sans commits non désirés et générés automatiquement.
Note: Tiré de l’impressionnant post de git-tower
. Le inconvénients} de rebase
est également une bonne lecture dans le même message.
Cette phrase comprend:
En général, le meilleur moyen d’obtenir le meilleur des deux mondes est de rebaser local les modifications que vous avez apportées mais que vous n'avez pas encore partagées avant de les envoyer nettoyer votre histoire, mais ne refaites jamais rien de ce que vous avez poussé quelque part.
Source: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge
Le livre pro git est une très bonne explication sur la page rebasing .
Fondamentalement, une fusion prendra 2 commits et les combinera.
Un rebase ira à l'ancêtre commun sur le 2 et appliquera les modifications les unes sur les autres. Cela crée une histoire plus «propre» et plus linéaire.
Mais lorsque vous rebasez, vous abandonnez les commits précédents et créez-en de nouveaux. Donc, vous ne devriez jamais rebasonner un dépôt qui est public. Les autres personnes travaillant sur le repo vous haïront.
Pour cette seule raison, je fusionne presque exclusivement. 99% du temps, mes succursales ne diffèrent pas beaucoup, alors s’il ya des conflits, ce n’est qu’à un ou deux endroits.
Cette réponse est largement orientée autour de Git Flow . Les tables ont été générées avec le générateur de table Nice ASCII , et les arbres de l'historique avec cette commande merveilleuse ( aliasé en tant que 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érents avec les arbres de l'historique. Voyez également la différence entre git merge
et git merge --no-ff
en premier (vous voulez généralement utiliser git merge --no-ff
car cela rapproche votre historique 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
vs git rebase
Premier point: toujours fusionner les fonctionnalités pour développer, ne jamais rebase développer à partir de fonctionnalités. Ceci est une conséquence de la règle d'or du changement de base :
La règle d'or de
git rebase
est de ne jamais l'utiliser sur public branches.
Ne rebase jamais ce que tu as poussé quelque part.
Personnellement, j’ajouterais: sauf s’il s’agit d’une branche technique ET que votre équipe est consciente des conséquences}.
Ainsi, la question de git merge
vs git rebase
s'applique presque uniquement aux branches de fonctionnalités (dans les exemples suivants, --no-ff
a toujours été utilisé lors de la fusion). Notez que, comme je ne suis pas sûr qu'il existe une meilleure solution ( un débat existe ), je ne fournirai que le comportement des deux commandes. Dans mon cas, je préfère utiliser git rebase
car cela produit un arbre historique plus agréable :)
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
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
git cherry-pick
Lorsque vous avez juste besoin d’un commit spécifique, git cherry-pick
est une solution intéressante (l’option -x
ajoute une ligne indiquant "(cherry tirée de commit ...)}" dans le corps du message de commit initial; bonne idée de l’utiliser - git log <commit_sha1>
pour le voir):
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
Pas sûr de pouvoir l'expliquer mieux que Derek Gourlay ... En gros, utilisez git pull --rebase
au lieu de git pull
:) Ce qui manque dans cet article, c'est que vous pouvez l'activer par défaut :
git config --global pull.rebase true
git rerere
Encore une fois, joliment expliqué ici . En termes simples, si vous l'activez, vous n'aurez plus à résoudre le même conflit plusieurs fois.
Git rebase est utilisé pour rendre les chemins de branchement dans le nettoyeur d'historique et la structure de référentiel linéaires.
Il est également utilisé pour garder les branches créées par vous privées, car après la modification de la base et le transfert des modifications au serveur, si vous supprimez votre branche, il n'y aura aucune preuve de la branche sur laquelle vous avez travaillé. Donc, votre succursale est maintenant votre préoccupation locale.
Après avoir fait rebase, nous nous débarrassons également d'un commit supplémentaire que nous avions l'habitude de voir si nous réalisions une fusion normale.
Et oui, il faut encore fusionner après une commande réussie, car la commande rebase place simplement votre travail au-dessus de la branche que vous avez mentionnée lors de la refonte dire master et effectue le premier commit de votre branche en tant que descendant direct de la branche master. Cela signifie que nous pouvons maintenant effectuer une fusion rapide pour transférer les modifications de cette branche vers la branche principale.
Quelques exemples pratiques, quelque peu liés au développement à grande échelle où gerrit est utilisé pour la révision et l’intégration de la livraison.
Je fusionne lorsque j'élève ma branche de fonctionnalités vers un nouveau maître distant. Cela donne un travail de soulèvement minimal et il est facile de suivre l'historique du développement des fonctionnalités, par exemple dans gitk.
git fetch
git checkout Origin/my_feature
git merge Origin/master
git commit
git Push Origin HEAD:refs/for/my_feature
Je fusionne lorsque je prépare un commit de livraison.
git fetch
git checkout Origin/master
git merge --squash Origin/my_feature
git commit
git Push Origin HEAD:refs/for/master
Je me rebase lorsque l'intégration de la validation de livraison échoue pour une raison quelconque et je dois la mettre à jour vers un nouveau maître distant.
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase Origin/master
git Push Origin HEAD:refs/for/master
Regardons un exemple. Tout en travaillant sur une branche nommée login
, sur la base de la branche master
, l'un des membres de votre équipe a appliqué certaines modifications à master
. Vous avez besoin de ces modifications pour terminer la fonction login
de votre branche.
Figure 1. Les nouveaux commits dans la branche master
(E et F) sont nécessaires pour terminer le travail dans la branche login
.
La fusion de la branche master
dans la vôtre aboutirait à une validation de fusion, qui comprend les modifications entre les deux branches et existe pour indiquer où une fusion est effectuée. s'est produite.
Figure 2. La fusion des deux branches donne lieu à un commit de fusion.
Nous n’aurons pas besoin de savoir quand nous avons fusionné la master
dans la branche login
à l’avenir. Au lieu de cela, nous voudrions prétendre que tous les commits sur la branche login
se sont produits en fonction du nouvel état de la branche master
.
La commande Git rebase rembobine temporairement les commits sur votre branche actuelle, les valide depuis l'autre branche et réapplique les commits rembobinés. En commutant le courant Ceci base la branche en cours sur l'autre branche.
Figure 3. Le changement de base applique les commits de la branche login
au-dessus de la branche master
.
La source est ici
On a expliqué à maintes reprises ce qu'est le rebase et la fusion, mais quand utiliser quoi?
Quand utiliser rebase?
Comme git rebase change l'histoire. Par conséquent, vous ne devriez pas l'utiliser quand quelqu'un d'autre travaille sur la même branche/si vous l'avez poussé. Toutefois, si vous avez une branche locale, vous pouvez créer un maître de base de fusion avant de fusionner votre branche en maître afin de conserver un historique plus propre. Ainsi, après la fusion dans la branche principale, il ne sera pas visible que vous ayez utilisé une branche dans la branche principale. L’historique est "plus propre", car vous n’avez pas automatiquement généré historique dans votre branche principale sans avoir généré automatiquement les modifications "fusionnées ..". Assurez-vous cependant que vous utilisez git merge feature-branch --ff-only
pour vous assurer qu'il n'y a pas de conflit créant un seul commit lorsque vous fusionnez votre fonctionnalité sur main.
Un deuxième scénario serait, si vous avez une branche à partir d'une branche et que vous voulez savoir ce qui a changé dans la branche principale. Rebase vous donne les informations car il inclut chaque commit.
Quand utiliser la fusion?
Lorsque vous n'avez pas besoin ou ne souhaitez pas disposer de l'historique d'une branche de fonctionnalités dans votre branche principale ou si d'autres personnes travaillent sur la même branche/vous l'avez poussée. Si vous souhaitez toujours avoir l'historique, fusionnez simplement le maître dans la branche de fonctionnalité avant de fusionner la branche de fonctionnalité dans le maître. Cela entraînera une fusion rapide dans laquelle vous aurez l'historique de la branche de fonctions dans votre maître (y compris la validation de fusion qui était dans votre branche de fonctions car vous y avez fusionné le maître).