Les branches font partie du cœur même de Git et constituent un de ses principaux atouts. C’est un moyen de travailler en parallèle sur d’autres fonctionnalités. C’est comme si vous aviez quelque part une « copie » du code source du site qui vous permet de tester vos idées les plus folles et de vérifier si elles fonctionnent avant de les intégrer au véritable code source de votre projet.
Bien que les branches soient « la base » de Git, je n’en ai pas parlé avant pour rester simple. Pourtant, il faut absolument les connaître et s’en servir. La gestion poussée des branches de Git est la principale raison qui incite les projets à passer à Git, donc il vaut mieux comprendre comment ça fonctionne et en faire usage, sinon on passe vraiment à côté de quelque chose.
Dans Git, toutes les modifications que vous faites au fil du temps sont par défaut considérées comme appartenant à la branche principale appelée « master » :
On voit sur ce schéma les commits qui sont effectués au fil du temps.
Supposons que vous ayez une idée pour améliorer la gestion des erreurs dans votre programme mais que vous ne soyez pas sûrs qu’elle va fonctionner : vous voulez faire des tests, ça va vous prendre du temps, donc vous ne voulez pas que votre projet incorpore ces changements dans l’immédiat.
Il suffit de créer une branche, que vous nommerez par exemple « idee_gestion_erreurs », dans laquelle vous allez pouvoir travailler
en parallèle :
À un moment donné, nous avons décidé de créer une nouvelle branche. Nous avons pu y faire des commits, mais cela ne nous a pas empêché de continuer à travailler sur la branche principale et d’y faire des commits aussi.
À la fin, mon idée s’est révélée concluante, j’ai largement amélioré la gestion des erreurs et j’ai donc intégré les changements dans la branche principale « master ». Mon projet dispose maintenant de mon idée que j’avais développée en parallèle.
Tous les commits de ma branche se retrouvent fusionnés dans la branche principale.
Git n’est pas le seul outil capable de gérer des branches, mais il est le seul à le faire
aussi bien. En effet, en temps normal vous pourriez tout simplement copier le répertoire de votre projet dans un autre dossier, tester les modifications et les incorporer ensuite dans le véritable dossier de votre projet. Mais cela aura nécessité de copier tous les fichiers et de se souvenir de tout ce que vous avez modifié. Et je ne vous parle même pas du cas où quelqu’un aurait modifié le même fichier que vous en même temps dans la branche principale !
Git gère tous ces problèmes pour vous. Au lieu de créer une copie des fichiers, il crée juste une branche « virtuelle » dans laquelle il retient vos changements en parallèle. Lorsque vous décidez de fusionner une branche (et donc de ramener vos changements dans « master » pour les valider), Git vérifie si vos modifications n’entrent pas en conflit avec des commits effectués en parallèle. S’il y a des conflits, il essaie de les résoudre tout seul ou vous avertit s’il a besoin de votre avis (c’est le cas si deux personnes ont modifié la même ligne d’un même fichier par exemple).
Ce concept de branches très légères qui ne nécessitent pas de copier les fichiers est d’une grande puissance. Cela vous encourage à créer des branches tout le temps, pour toutes les modifications qui pourraient prendre du temps avant d’être terminées.
Vous pouvez même créer une sous-branche à partir d’une branche !
Dans le cas ci-dessus, ma sous-branche ne s’est pas révélée concluante ; j’ai donc dû la supprimer et aucun des commits intermédiaires ne sera finalement incorporé à la branche principale du projet.
Les branches locales
Tout le monde commence avec une seule branche « master » : c’est la branche principale. Jusqu’ici, vous avez donc travaillé dans la branche « master », sur le « vrai » code source de votre projet.
Pour voir toutes vos branches, tapez ceci :
Code : Console
Vous verrez normalement uniquement « master » :
Code : Console
Il y a une étoile devant pour indiquer que c’est la branche sur laquelle vous êtes actuellement.
Pourquoi créer une branche et quand dois-je en créer une ?
Lorsque vous vous apprêtez à faire des modifications sur le code source, posez-vous les questions suivantes :
- « Ma modification sera-t-elle rapide ? » ;
- « Ma modification est-elle simple ? » ;
- « Ma modification nécessite-t-elle un seul commit ? » ;
- « Est-ce que je vois précisément comment faire ma modification d’un seul coup ? ».
Si la réponse à l’une de ces questions est « non », vous devriez probablement créer une branche. Créer une branche est très simple, très rapide et très efficace. Il ne faut donc pas s’en priver.
Créez une branche pour toute modification que vous vous apprêtez à faire et qui risque d’être un peu longue.
Au pire, si votre modification est plus courte que prévu, vous aurez créé une branche « pour pas grand-chose », mais c’est toujours mieux que de se rendre compte de l’inverse.
Créer une branche et changer de branche
Supposons que vous vouliez « améliorer la page des options membres » du code de votre site. Vous n’êtes pas sûrs du temps que cela va prendre, ce n’est pas un changement simple qui consiste à modifier deux-trois liens et vous risquez de faire plusieurs commits. Bref, il faut créer une branche pour cela.
Code : Console | git branch options_membres |
Cela crée une branche appelée « options_membres ». Il est important de noter que cette branche est locale : vous seuls y avez accès (il est néanmoins possible de publier une branche pour que d’autres personnes puissent vous aider, mais ce n’est pas le sujet pour le moment).
Une fois la branche créée, vous devriez la voir quand vous tapez simplement
git branch :
Code : Console | $ git branch
* master
options_membres |
Comme vous pouvez le voir, vous êtes toujours sur la branche « master ». Pour aller sur la branche « options_membres », tapez ceci :
Code : Console | git checkout options_membres |
git checkout est utilisé pour changer de branche mais aussi pour restaurer un fichier tel qu’il était lors du dernier commit. La commande a donc un double usage.
Qu’est-ce qui se passe lorsque l’on change de branche ? En fait, vous ne changez pas de dossier sur votre disque dur, mais Git change vos fichiers pour qu’ils reflètent l’état de la branche dans laquelle vous vous rendez. Imaginez que les branches dans Git sont comme des dossiers virtuels : vous « sautez » de l’un à l’autre avec la commande
git checkout. Vous restez dans le même dossier, mais Git modifie les fichiers qui ont changé entre la branche où vous étiez et celle où vous allez.
Faites maintenant des modifications sur les fichiers, puis un commit, puis d’autres modifications, puis un commit, etc. Si vous faites
git log, vous verrez tous vos récents commits.
Maintenant, supposons qu’un bug important ait été détecté sur votre site et que vous deviez le régler immédiatement. Revenez sur la branche « master », branche principale du site :
Code : Console
Faites vos modifications, un commit, éventuellement un push s’il faut publier les changements de suite, etc.
Ensuite, revenez à votre branche :
Code : Console | git checkout options_membres |
Si vous faites un
git log, vous verrez que le commit que vous avez effectué sur la branche « master » n’apparaît pas. C’est en cela que les branches sont distinctes.
Fusionner les changements
Lorsque vous avez fini de travailler sur une branche et que celle-ci est concluante, il faut « fusionner » cette branche vers « master » avec la commande
git merge.
Avec Git, on peut fusionner n’importe quelle branche dans une autre branche, bien que le plus courant soit de fusionner une branche de test dans « master » une fois que celle-ci est concluante.
Supposons que vous ayez fini votre travail dans la branche « options_membres » et que vous vouliez maintenant le publier. Pour cela, il faut fusionner le contenu de la branche « options_membres » dans la branche principale « master ».
Rendez-vous d’abord dans la branche « master » :
Code : Console
Demandez ensuite à y intégrer le travail que vous avez fait dans « options_membres » :
Code : Console | git merge options_membres |
Tous vos commits de la branche « options_membres » se retrouvent maintenant dans « master » ! Vous avez pu travailler en parallèle sans gêner la branche principale, et maintenant que votre travail est terminé vous l’avez appliqué sur « master » !
Lorsque vous récupérez les nouveaux commits depuis le serveur avec git pull, cela revient en fait à appeler deux commandes différentes : git fetch, qui s’occupe du téléchargement des nouveaux commits, et git merge, qui fusionne les commits téléchargés issus de la branche du serveur dans la branche de votre ordinateur !
Votre branche « options_membres » ne servant plus à rien, vous pouvez la supprimer :
Code : Console | git branch -d options_membres |
Git vérifie que votre travail dans la branche « options_membres » a bien été fusionné dans « master ». Sinon, il vous en avertit et vous interdit de supprimer la branche (vous risqueriez sinon de perdre tout votre travail dans cette branche !).
Si vraiment vous voulez supprimer une branche même si elle contient des changements que vous n’avez pas fusionnés (par exemple parce que votre idée à la base était une erreur), utilisez l’option
-D (lettre capitale) :
Code : Console | git branch -D options_membres /!\ Supprime la branche et perd tous les changements. |
Mettre de côté le travail en cours avant de changer de branche
Cette section est un peu complexe. Je vous recommande de réserver sa lecture pour plus tard.
Avant de changer de branche, vous devez avoir effectué un commit de tous vos changements. En clair, un
git status ne devrait afficher aucun fichier en cours de modification.
Si vous avez des changements non « commités » et que vous changez de branche, les fichiers modifiés resteront comme ils étaient dans la nouvelle branche (et ce n’est en général pas ce que vous voulez !).
Pour éviter d’avoir à faire un commit au milieu d’un travail en cours, tapez :
Code : Console
Vos fichiers modifiés seront sauvegardés et mis de côté. Maintenant,
git status ne devrait plus afficher aucun fichier (on dit que votre
working directory est propre).
Vous pouvez alors changer de branche, faire vos modifications, « committer », puis revenir sur la branche où vous étiez.
Code : Console | git checkout master
(modifier des fichiers)
git commit -a
git checkout mabranche |
Pour récupérer les changements que vous aviez mis de côté dans « mabranche », tapez :
Code : Console
Vos fichiers seront alors restaurés et se retrouveront donc l’état dans lequel ils étaient avant le
git stash !
Les branches partagées
Il est possible de travailler à plusieurs sur une même branche. En fait, c’est déjà ce que vous faisiez en travaillant sur la branche « master ».
Utilisez
git branch -r pour lister toutes les branches que le serveur connaît :
Code : Console | $ git branch -r
origin/HEAD
origin/master |
origin, c’est le nom du serveur depuis lequel vous avez cloné le dépôt (par exemple celui de GitHub). Vous pouvez en théorie suivre directement les branches de plusieurs personnes (souvenez-vous, Git fonctionne un peu comme le peer-to-peer), mais on travaille plutôt avec un serveur pour suivre les changements.
Si on met de côté « HEAD » qui est un peu particulier, on voit qu’il y a une seule branche sur le serveur : « master ». Le serveur ne connaît donc que l’historique de la branche principale.
Si le serveur possède une autre branche, par exemple « origin/options_membres », et que vous souhaitez travailler dessus, il faut créer une copie de cette branche sur votre ordinateur qui va « suivre » (on dit
tracker) les changements sur le serveur.
Code : Console | git branch --track branchelocale origin/brancheserveur |
Par exemple, vous pouvez créer une branche « options_membres » locale qui sera connectée à la branche « options_membres » du serveur :
Code : Console | git branch --track options_membres origin/options_membres |
Lorsque vous ferez un pull depuis la branche « options_membres », les changements seront fusionnés dans votre « options_membres » local. Il est donc important de savoir dans quelle branche vous vous trouvez avant de faire un pull. Un pull depuis la branche « master » met à jour votre branche « master » locale en fonction de ce qui a changé sur le serveur, et il en va de même pour n’importe quelle autre branche.
Ajouter ou supprimer une branche sur le serveur
Il est possible d’ajouter des branches sur le serveur pour y travailler à plusieurs, mais il faut reconnaître que la syntaxe proposée par Git est tout sauf claire à ce niveau.
Voici comment on ajoute une branche sur le serveur :
Code : Console | git push origin origin:refs/heads/nom_nouvelle_branche |
Vous pouvez ensuite créer une branche locale qui « suit » la branche du serveur avec
git branch --track, comme nous l’avons vu précédemment.
Pour supprimer une branche sur le serveur :
Code : Console | git push origin :heads/nom_branche_a_supprimer |
À noter que les «
remote tracking branches » (celles qui apparaissent lorsqu’on fait
git branch -r) ne seront pas automatiquement supprimées chez les autres clients. Il faut qu’ils les suppriment manuellement à l’aide de la commande suivante :
Code : Console | git branch -r -d origin/nom_branche_a_supprimer |