# 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), et sinon de faire automatiquement un rebase : ```git git config pull.rebase true ``` 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. Pour créer une branche fille à partir de la branche sur laquelle vous êtes : ```git git checkout -b nom_de_la_nouvelle_branche ``` Et pour basculer de branche en branche : ```git git checkout nom_de_la_branche ``` Si vous ne savez pas sur quelle branche vous vous trouvez, vous pouvez faire : ```git git branch ``` ## 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. Pour fusionner une branche dans celle sur laquelle vous vous trouvez : ```git git merge nom_de_la_branche_à_fusionner_dans_celle_sur_laquelle_vous_êtes ``` ## 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, et sinon, de rebase notre branche automatiquement : ```git git config pull.rebase true ``` 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 profondeur) : [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).