Added git flow article
Signed-off-by: Louis Vallat <louis@louis-vallat.xyz>
This commit is contained in:
parent
c4f4986fe4
commit
8fa638fdd5
3
src/assets/images/git_flow/git_rebase.svg
Normal file
3
src/assets/images/git_flow/git_rebase.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
218
src/git_flow.md
Normal file
218
src/git_flow.md
Normal file
@ -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).
|
Loading…
Reference in New Issue
Block a user