Expliquer les branches Git avec une analogie LEGO
Utilisez cette analogie LEGO utile pour comprendre pourquoi il est important de créer une branche dans Git.
Créer une nouvelle branche dans un référentiel de code est une tâche assez courante lorsque l'on travaille avec Git. C'est l'un des principaux mécanismes permettant de séparer les modifications non liées les unes des autres. C'est aussi très souvent le désignateur principal de ce qui est fusionné dans la branche principale.
Sans branches, soit tout devrait être sélectionné, soit tout votre travail serait fusionné efficacement sous la forme d'un rebase écrasé. Le problème est que les branches héritent du travail de la branche à partir de laquelle elles sont dérivées, ce qui peut vous amener à pousser accidentellement des validations que vous n'aviez jamais prévu d'être dans votre nouvelle branche.
La solution est de toujours débrancher du main (sauf si vous avez l'intention de ne pas le faire). C'est une règle facile à énoncer, mais malheureusement, elle est tout aussi facile à oublier. Il peut donc être utile d'examiner le raisonnement qui se cache derrière cette règle.
Une branche n'est pas un dossier
Il est naturel de considérer une branche Git comme un dossier.
Ce n'est pas.
Lorsque vous créez une branche, vous ne créez pas un environnement propre, même si cela semble être le cas. Une branche hérite de toutes les données contenues dans son parent. Si la branche parent est la branche principale, alors votre nouvelle branche contient l'historique commun de votre projet. Mais si la branche parent est une autre branche hors de main, alors votre nouvelle branche contient l'historique de main plus l'historique de l'autre branche. Je pense souvent en termes de briques LEGO, alors voici un exemple visuel qui n'est pas l'un de ces graphiques de nœuds Git complexes (mais qui l'est en fait, secrètement).
Disons que votre branche principale est une plaque LEGO.
(Seth Kenlon CC BY-SA 4.0)
Lorsque vous créez une branche hors de main
, vous ajoutez une brique. Supposons que vous ajoutiez une branche appelée blue
.
(Seth Kenlon BY-SA 4.0)
La branche blue
contient l'historique de la plaque de base ainsi que tout le travail que vous effectuez sur blue
. Dans le code, voici ce qui s'est passé jusqu'à présent :
$ git branch
* main
$ git checkout -b blue
Branche d'une succursale
Si vous créez encore une autre branche alors que vous êtes toujours dans votre branche blue
, alors vous construisez au-dessus de main
ainsi que de blue
. . Supposons que vous créiez une branche appelée red
parce que vous souhaitez commencer à créer une nouvelle fonctionnalité.
(Seth Kenlon CC BY-SA 4.0)
Il n'y a rien de mal en soi à cela, tant que vous comprenez que votre branche red
est construite sur blue
. Tout le travail que vous avez effectué dans la branche bleu
existe également en rouge
. Tant que vous ne souhaitez pas que red
soit un nouveau départ contenant uniquement l'historique de votre branche main
, c'est une méthode parfaitement acceptable de construire votre dépôt. Sachez cependant que le propriétaire du projet n'est pas en mesure, par exemple, d'accepter les modifications rouges
sans également accepter un ensemble de modifications bleues
, du moins pas sans passer par à beaucoup d'ennuis.
Pause propre
Si ce que vous voulez réellement faire est de développer bleu
et rouge
en tant que fonctionnalités distinctes afin que le propriétaire du projet puisse choisir de fusionner l'une et pas l'autre, alors vous avez besoin des deux. les branches doivent toutes deux être basées uniquement sur main
. C'est facile à faire. Il vous suffit de commencer par extraire la branche main
, puis de créer votre nouvelle branche à partir de là.
$ git branch
* blue
main
$ git checkout main
$ git checkout -b red
Voici à quoi cela ressemble en LEGO :
(Seth Kenlon CC BY-SA 4.0)
Vous pouvez désormais fournir uniquement du bleu
au propriétaire du projet, ou simplement du rouge
, ou les deux, et le propriétaire du projet peut décider quoi attacher à main
. sur le dépôt officiel. Mieux encore, blue
et red
peuvent être développés séparément à l'avenir. Même si vous terminez blue
et qu'il est fusionné dans main
, une fois que le développeur de red
fusionne les modifications de main
alors ce qui était bleu
devient disponible pour le nouveau développement rouge
.
(Seth Kenlon CC BY-SA 4.0)
Exemple de branche
Voici une démonstration simple de ce principe. Tout d’abord, créez un dépôt Git avec une branche principale :
$ mkdir example
$ cd example
$ git init -b main
Remplissez votre projet naissant avec un exemple de fichier :
$ echo "Hello world" > example.txt
$ git add example.txt
$ git commit -m 'Initial commit'
Ensuite, extrayez une branche appelée blue
et faites un commit idiot que vous ne voulez pas conserver :
$ git checkout -b blue
$ fortune > example.txt
$ git add example.txt
$ git commit -m 'Unwisely wrote over the contents of example.txt'
Jetez un œil au journal :
$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit
Tout d'abord, supposons que vous êtes heureux de continuer à développer sur blue
. Créez une branche appelée red
:
$ git checkout -b red
Jetez un œil au journal :
$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit
Votre nouvelle branche red
, et tout ce que vous développez en red
, contient le commit que vous avez effectué en blue
. Si c'est ce que vous souhaitez, vous pouvez alors procéder au développement. Cependant, si vous avez l'intention de prendre un nouveau départ, vous devez plutôt créer red
à partir de main
.
Maintenant, vérifiez votre branche principale :
$ git checkout main
Jetez un œil au journal :
$ git log --oneline
55d4811 Initial commit
Ça a l'air bien jusqu'à présent. La branche blue
est isolée de main
, c'est donc une base propre à partir de laquelle bifurquer dans une direction différente. Il est temps de réinitialiser la démo. Parce que vous n'avez encore rien fait sur red
, vous pouvez le supprimer en toute sécurité. Si cela se produisait dans la vraie vie et que vous aviez commencé à développer sur red
, vous devrez alors sélectionner vos modifications du rouge vers une nouvelle branche.
Ceci n'est qu'une démo, vous pouvez donc supprimer red
en toute sécurité :
$ git branch -D red
Créez maintenant une nouvelle branche appelée red
. Cette version du rouge
est conçue comme un nouveau départ, distinct du bleu
.
$ git checkout -b red
$ git log --oneline
55d4811 Initial commit
Essayez de faire un nouveau commit :
$ echo "hello world" >> example.txt
$ git add example.txt
$ git commit -m 'A new direction'
Regardez le journal :
$ git checkout -b red
$ git log --oneline
de834ff A new direction
55d4811 Initial commit
Jetez un dernier coup d'œil au bleu
:
$ git checkout blue
$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit
La branche rouge
a sa propre histoire.
Le bleu
a sa propre histoire.
Deux branches distinctes, toutes deux basées sur main
.
Fourchette avec précaution
Comme beaucoup d'utilisateurs de Git, je trouve plus facile de suivre ma branche actuelle en utilisant une invite compatible Git. Après avoir lu l'article de Moshe Zadka à ce sujet, j'utilise Starship.rs et je l'ai trouvé très utile, en particulier lors de nombreuses mises à jour d'un projet d'empaquetage qui nécessite que toutes les demandes de fusion contiennent un seul commit sur exactement un. bifurquer.
Avec des centaines de mises à jour effectuées sur 20 participants ou plus, la seule façon de gérer cela est de vérifier souvent, d'extraire et de créer une nouvelle branche. Starship me rappelle instantanément ma branche actuelle et l'état de cette branche.
Que vous dériviez d'une nouvelle branche à partir de la branche principale ou à partir d'une autre branche dépend de ce que vous essayez d'accomplir. L’important est que vous compreniez que l’endroit où vous créez une succursale est important. Faites attention à votre branche actuelle.