Expliquer les branches Git avec une analogie LEGO

La création d’une nouvelle branche dans un référentiel de code est une tâche assez courante lorsque vous travaillez 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, tout devrait soit être trié sur le volet, soit tout votre travail serait fusionné efficacement en tant que rebase écrasée. Le problème est que les branches héritent du travail de la branche à partir de laquelle elles sont dérivées, et cela peut vous amener à pousser accidentellement des commits que vous n’aviez jamais prévu d’être dans votre nouvelle branche.
La solution est de toujours bifurquer du principal (sauf si vous voulez dire non). C’est une règle facile à dire, mais malheureusement, c’est tout aussi facile à oublier, il peut donc être utile d’examiner le raisonnement derrière la règle.
Contents
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 peut sembler être le cas. Une branche hérite de toutes les données que contient 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 à partir de main
, vous ajoutez une brique. Supposons que vous ajoutiez une branche appelée blue
.
(Seth Kenlon BY-SA 4.0)
Le blue
branche contient l’historique de la plaque de base ainsi que tout 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
Succursale d’une succursale
Si vous créez encore une autre branche alors que vous êtes encore dans votre blue
branche, alors vous construisez au-dessus de main
ainsi que blue
. Supposons que vous créez une branche appelée red
parce que vous voulez commencer à créer une nouvelle fonctionnalité.
(Seth Kenlon CC BY-SA 4.0)
Il n’y a rien de mal à cela, tant que vous comprenez que votre red
la branche est construite au-dessus de blue
. Tout le travail que vous avez fait dans le blue
branche existe aussi en red
. Tant que tu ne voulais pas red
être un nouveau départ contenant seul l’histoire de votre main
branch, il s’agit d’une méthode parfaitement acceptable pour créer votre dépôt. Sachez toutefois que le porteur de projet ne peut pas, par exemple, accepter le red
changements sans accepter également un tas de blue
changements, du moins pas sans se donner beaucoup de mal.
Pause propre
Si ce que vous voulez réellement faire, c’est développer blue
et red
en tant que fonctionnalités distinctes afin que le propriétaire du projet puisse choisir de fusionner l’une et non l’autre, alors vous avez besoin que les deux branches soient basées uniquement sur main
. C’est facile à faire. Vous venez de vérifier le main
branche d’abord, puis créez votre nouvelle branche à partir de là.
$ git branch
* blue
main
$ git checkout main
$ git checkout -b red
Voici à quoi cela ressemble dans LEGO :
(Seth Kenlon CC BY-SA 4.0)
Maintenant, vous pouvez livrer juste blue
au maître d’ouvrage, ou simplement red
ou les deux, et le propriétaire du projet peut décider quoi joindre à main
sur le dépôt officiel. Mieux encore, les deux blue
et red
peuvent être développés séparément à l’avenir. Même si tu finis blue
et il est fusionné dans main
une fois le développeur de red
fusionne dans les changements de main
alors qu’est-ce qui était blue
devient accessible aux nouveaux red
développement.
(Seth Kenlon CC BY-SA 4.0)
Exemple de branche
Voici une démonstration simple de ce principe. Commencez par créer 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, passez à la caisse d’une succursale appelée blue
et faites un commit stupide que vous ne voulez pas garder :
$ 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 en plus de 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 nouveau red
branche, et tout ce que vous développez dans red
contient le commit que vous avez fait dans blue
. Si c’est ce que vous voulez, vous pouvez poursuivre le développement. Cependant, si vous aviez l’intention de prendre un nouveau départ, vous devez créer red
hors du main
Au lieu.
Vérifiez maintenant 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. Le blue
la branche est isolée de main
, c’est donc une base propre à partir de laquelle se ramifier dans une direction différente. Il est temps de réinitialiser la démo. Parce que vous n’avez rien fait sur red
pourtant, 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 dans une nouvelle branche.
Il ne s’agit que d’une démo, vous pouvez donc la supprimer en toute sécurité red
:
$ git branch -D red
Créez maintenant une nouvelle branche appelée red
. Cette version de red
se veut un nouveau départ, distinct de blue
.
$ git checkout -b red
$ git log --oneline
55d4811 Initial commit
Essayez de créer 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’oeil à blue
:
$ git checkout blue
$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit
Le red
branche a une histoire qui lui est propre.
Le blue
a une histoire qui lui est propre.
Deux branches distinctes, toutes deux basées sur main
.
Fourchette avec soin
Comme de nombreux utilisateurs de Git, je trouve plus facile de suivre ma branche actuelle en utilisant une invite compatible avec Git. Après avoir lu l’article de Moshe Zadka à ce sujet, j’ai utilisé Starship.rs et je l’ai trouvé très utile, en particulier lors de la mise à jour de nombreuses mises à jour d’un projet d’emballage qui nécessite que toutes les demandes de fusion contiennent un seul commit sur exactement un une succursale.
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 la main, de tirer et de créer une nouvelle branche. Starship me rappelle instantanément ma branche actuelle et l’état de cette branche.
Que vous bifurquiez 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 branche est important. Soyez conscient de votre succursale actuelle.