From 8fa638fdd5147b610c7233ba6035d0d4faccb866 Mon Sep 17 00:00:00 2001 From: Louis Vallat Date: Thu, 18 Mar 2021 23:39:30 +0100 Subject: [PATCH] Added git flow article Signed-off-by: Louis Vallat --- src/assets/images/git_flow/git_rebase.svg | 3 + src/git_flow.md | 218 ++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 src/assets/images/git_flow/git_rebase.svg create mode 100644 src/git_flow.md diff --git a/src/assets/images/git_flow/git_rebase.svg b/src/assets/images/git_flow/git_rebase.svg new file mode 100644 index 0000000..d3e6a02 --- /dev/null +++ b/src/assets/images/git_flow/git_rebase.svg @@ -0,0 +1,3 @@ + + +
Matser
Matser
new_feature
new_fe...
Matser
Matser
new_feature
new_fe...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/src/git_flow.md b/src/git_flow.md new file mode 100644 index 0000000..40f99e7 --- /dev/null +++ b/src/git_flow.md @@ -0,0 +1,218 @@ +# Git Workflow + +> À noter que ce guide est destiné aux personnes qui ont déjà utilisé git auparavant, +> il ne s'agit pas ici d'un tutoriel pour débutants (bien que je sois ici assez +> exhaustif dans mes explications). + +Git est un outil de versionnage très utile, voici comment je m'en sers. + +[TL;DR](#TL;DR) + +## Les fondations + +Vous êtes bien installé devant votre écran, les doigts ne demandent qu'à +furieusement taper les touches de votre clavier, mais avant le top départ, il faut +préparer le terrain ! Voici quelques commandes **primordiales** (pour ne pas dire +**obligatoires**) à réaliser avant de se lancer dans un projet. + +Premièrement, je n'aime pas la manière qu'a git de faire des commits de fusion +lors d'un pull qui se passe mal (divergence entre votre version locale et distante +par exemple, aka. vous avez committé et quelqu'un d'autre aussi en même temps). +Nous allons donc demander à git de ne pull que lorsque l'historique est linéaire +(fast-forward) : + +```git +git config pull.ff only +``` + +En cas de divergence, un simple `git rebase origin/branche_concernée` vous sortira +d'affaire ! + +Ensuite, il nous arrive de vouloir avoir une vue plus graphique de notre historique +git. Voici un alias, à placer dans votre `~/.gitconfig`, qui vous permet d'afficher +un graphique de vos branches et vos commits de manière plus visuelle que le `git log` +de base de git (honteusement volés [ici](https://stackoverflow.com/a/9074343)) : + +```git +[alias] + lg1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all + lg2 = log --graph --abbrev-commit --decorate --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)' --all + lg = !"git lg1" +``` + +Si vous n'avez pas besoin d'autant de décorations, ou que vous ne pouvez pas définir +d'alias, cette commande fait quelque chose d'assez similaire : + +```git +git log --all --decorate --oneline --graph +``` + +## Des branches, des branches, et encore des branches + +Quand on travaille à plusieurs sur git, il devient presque obligatoire d'avoir +des branches pour éviter de se sentir "à l'étroit" dans son `repo`. Pour pouvoir +collaborer et avancer sur un projet en groupe sans se marcher sur les pieds les +uns des autres, les branches deviennent l'outil indispensable de git. + +J'utilise les branches de la manière suivante : + +- les branches ont une durée de vie **très courte** +- une fois que la branche a rempli son rôle et qu'elle a été fusionnée, elle doit être supprimée +- une branche par fonctionnalité ou par résolution de problème + - les noms des branches sont libres *tant qu'ils sont clairs* + - c'est mieux d'avoir comme nom la fonctionnalité développée ou son rôle + - lorsqu'une branche sert à développer une résolution de bug ou un `fix`, il est mieux de l'inclure dans le nom + - lorsque vous travaillez à plusieurs sur la même fonctionnalité, il est conseillé de + faire une branche par personne en partant de la branche princpale de cette fonctionnalité + +Évidemment, une branche fait exception : `master` (ou `main`, peu importe), +qui est une version "propre", "stable", et qui doit présenter le projet dans un état +fonctionnel, tel qu'il serait montré à un client ou à un responsable. + +Il est possible d'avoir une seconde branche sur les projets plus importants, qui se +nomme alors `develop` et qui est la version en développement actif d'un projet, +mais qui ne peut pas être fusionnée sur la branche princpale pour des raisons de +stabilité par exemple, ou qui n'est pas prête pour la mise en production. + +## Rebaser, c'est la clef + +> Cette partie peut être ignorée si vous ne pouvez pas réaliser de `push force` +> (ou équivalent). En effet, un `rebase` modifie fondamentalement l'historique de +> votre git. Si vous n'êtes pas sûr de vous, n'en faites pas. Je ne suis pas +> responsable si vous perdez des données. + +Votre fonctionnalité est développée et testée, vous voulez la fusionner avec votre +branche parente ? Vous voulez récupérer ce qui est sur votre branche parente et +que vous aimeriez récupérer sur la votre ? Il est temps de rebase ! + +Lorsque l'on crée une branche, celle-ci a un `commit` de "départ", depuis lequel +elle se *base* pour faire du versionnage en parallèle des autres branches. Parfois +il est nécessaire de récupérer du travail qui a été mis sur la branche mère dans +notre branche de travail, par exemple la résolution d'un bogue handicapant. + +Un `rebase` va faire changer votre commit de départ et l'échanger avec un autre. +Prenons le schéma suivant : + +![Schéma d'un rebase](assets/images/git_flow/git_rebase.svg) + +Nous avons ici la branche `new_feature` qui part d'un commit de master. Disons +que vous êtes en train de développer une fonctionnalité importante, et qu'un bug +vous ralentit dans l'exécution de vos tests, mais qu'il a été réglé après la création +de votre branche, et qu'il est disponible sur `master`. Pour le récupérer sur votre +branche, vous n'avez qu'à `rebase` votre branche sur la dernière version de `master`. +La commande pour faire ceci serait alors : + +```git +git rebase nom_de_branche_parente +``` + +Il est important de noter que vous risquez d'avoir des conflits au cours de cette +opération. En cas de conflit, vous pouvez les régler, puis faire `git add fichier_en_conflit` +et enfin `git rebase --continue`. Cela aura pour effet de **réécrire** l'historique +git de votre branche, d'où l'importance de faire un push en force, puisque votre +version locale et la/les version(s) distante(s) n'auront plus rien à voir. + +### Quel rapport avec ce git flow + +Comme dit plus haut, les branches ont une existence précise et bien définie dans +le temps. Une branche n'a pas a être fusionnée dans sa branche parente tant que +son contenu n'est pas complet, ou au moins utilisable. Cela ne fait pas vraiment +de sens de "polluer" une branche parente dans le seul but d'en récupérer le nouveau +contenu. Les opérations de rebase sont donc ici fréquentes. + +## Fusion non préparée = fusion refusée + +Votre fonctionnalité ou correctif est terminé(e), votre branche est prête à être +fusionnée ? En vérité, pas tout à fait. Il faut maintenant préparer la fusion ! + +Afin de faciliter au maximum la fusion de votre branche, il va falloir faire un +dernier rebase. Le but de ce rebase est ici de vérifier que le rôle de la branche +et du contenu qu'elle propose sont toujours fonctionnels et qu'aucun bogue n'a été +intruduit par les nouveautés disponibles sur la branche parente. Cela va aussi +vous permettre de gérer les conflits avec la branche mère au sein même de la votre. +Une fusion n'introduira donc pas de bogue, et vous restez pleinement responsable +de votre branche. + +Enfin, vous n'êtes pas responsables de la fusion, un collègue ou responsable va +d'abord vérifier votre code et le contenu que vous apportez et approuver (ou rejeter) +la fusion que vous demandez. Grâce aux opérations de rebasage successifs que vous +avez fait durant la durée de vie de votre branche, la fusion se fera sans encombre. + +À noter que si vous avez des outils tels que les [Merge Requests](https://docs.gitlab.com/ee/user/project/merge_requests/getting_started.html) +chez GitLab, ou [Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) +chez GitHub, n'hésitez surtout pas à les utiliser ! Ces outils permettront de garder +un suivi des fusions, et d'expliquer son but à un responsable qui ne les a pas +forcément toutes en tête. + +## Au revoir vieille branche + +> Les opérations décrites ici peuvent entraîner une perte de code. Je ne suis pas +> responsable si vous supprimez une branche avant qu'elle n'ait été fusionnée. +> Ne supprimez une branche que si vous êtes sûr qu'elle n'a plus d'utilité. + +Votre branche est désormais fusionnée ? C'est la fin pour elle, il est désormais +temps de lui dire au revoir ! + +Commençons d'abord par la supprimer sur le repo distant : + +```git +git push -d origin nom_de_branche +``` + +Ici, le serveur distant s'appelle `origin`, comme c'est le cas la plupart du temps. + +Vos collègues peuvent synchroniser leurs branches et faire disparaître leurs +références locales à des branches fantômes distantes avec la commande `git fetch -p` (le +`-p` étant ici pour "prune"). + +Enfin, il est temps de supprimer votre copie locale de cette branche : + +```git +git branch -d nom_de_branche +``` + +À noter que le `-d` ne supprimera votre branche que si elle a été fusionnée. Il est +possible de forcer la suppression d'une branche locale non fusionnée avec l'option +`-D` qui équivaut à un `git --delete --force` sur la branche. + +"Don't cry because it's over, smile because it happened." - *Dr. Seuss* + +## TL;DR + +On commence par demander à git de ne pull que s'il n'y a pas de divergence avec +la version distante de notre branche : + +```git +git config pull.ff only +``` + +Ensuite on utilise une branche par fonctionnalité et par correctif. Une branche a +un rôle précis et une durée de vie très courte. Lorsque plusieurs développeurs +travaillent sur la même branche, ils ne doivent pas exclure la possibilité de créer +des branches personnelles. + +`master` est en tous temps propre et présentable. Une branche intermédiaire peut +être utilisée pour éviter de polluer inutilement la branche principale. Elle pourra +s'appeler `develop` par exemple. + +Les rebase sont fréquents et servent à récupérer sur une branche fille du nouveau +contenu de sa branche mère. + +La fusion se déroule sans accroc, un rebase doit être fait avant pour gérer les +conflits sur la branches fille. + +Une fois la branche fusionnée, elle doit être supprimée. + +## Informations supplémentaires + +### Vocabulaire + +- `repo` : raccourci de `repository`, qui est l'environnement de travail de git, + c'est là dedans que l'on créé ses branches, et que l'on versionne son travail. + +### Pour aller plus loin + +- Le fonctionnement des objets, commits et arbres sur git (en profondeurn): [vidéo](https://youtu.be/MyvyqdQ3OjI). +- Le fonctionnement des branches sur git (en profondeur) : [vidéo](https://youtu.be/mhZQRBp8dXE). +- Comment git stocke son arborescence de fichiers : [article](https://book.git-scm.com/book/en/v2/Git-Internals-Git-Objects). +- Les commandes associées à `git branch` : [documentation](https://git-scm.com/docs/git-branch).