Git/Branches
Précédemment, nous avons vu comment apporter des modifications à une branche telles que ajouter, modifier ou supprimer un fichier et commit
nos modifications. Cela fonctionne parfaitement et cela peut suffire pour travailler seul sur un petit projet. Toutefois, ce n'est pas la meilleure façon de procéder sous git qui propose des mécanismes plus élaborés pour développer sur un projet.
L'approche de git est de favoriser l'utilisation de branche pour toute modification du code de l'application.
Ainsi, il ne faut jamais travailler directement sur la branche *master* : cette branche doit rester stable et ne doit être utilisée que pour baser son travail dans d'autres branches.
Pour mieux comprendre, nous allons refaire, pas à pas, exactement les mêmes modifications que celles que nous avons faites précédemment mais, cette fois, nous allons utiliser une branche afin de nous familiariser avec ce concept.
Reprenons notre dépôt d'exemple :
git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
cd examples
Créer une première branche
[modifier | modifier le wikicode]D'abord, demandons à git de nous indiquer où nous en sommes au niveau des branches :
git branch
* master
Git nous indique qu'il existe une seule branche appelée master
et que c'est sur cette branche que nous travaillons comme l'indique l'astérisque en face de master
.
Créons une nouvelle branche que nous allons appeler ma-branche
.
git branch ma-branche
Constatons les effets :
git branch ma-branche
ma-branche * master
Il y a maintenant deux branches : *master* et *ma-branche*. Actuellement, nous travaillons toujours sur *master* comme l'indique toujours l'astérisque.
git log --decorate --graph
On peut voir, sur la première ligne que *master* et *ma-branche* sont au même niveau, sur le même commit. Nous allons maintenant demander à git de nous basculer sur *ma-branche* afin de pouvoir travailler sur celle-ci et non sur *master*.
git checkout ma-branche
Switched to branch 'ma-branche'
On a basculé, et git branch
nous le confirme.
git branch
* ma-branche master
git checkout -b ma-branche
pour créer et sélectionner une nouvelle branche en même temps.git checkout -f branche2
. Cela évite de faire un git clean -f -d
(discard all) avant.
git checkout .
supprime le code non commité.
Faire les modifications
[modifier | modifier le wikicode]On peut désormais faire les modifications dans ma-branche que l'on peut développer, sans prendre le risque de modifier master.
Faisons les mêmes modifications que précédemment :
echo "Ceci est un test de git" > mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'un fichier"
echo "Une seconde ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une seconde ligne dans le fichier"
echo "Une troisième ligne" >> mon_nouveau_fichier.txt
git add mon_nouveau_fichier.txt
git commit -m "ajout d'une troisième ligne dans le fichier"
Et ainsi de suite. Vous pouvez commiter et faire autant de commits que vous voulez dans ma-branche.
L'idée est que pour chaque évolution du logiciel développé, il faut créer une branche. Ainsi, on peut garder la branche aussi longtemps que nécessaire et continuer de travailler dessus tant qu'on a pas fini la fonctionnalité.
Regardons le log
que cela produit :
git log --decorate --graph
* commit 635ace69f901dfb1aaff187e6abc54b0c95fe51e (HEAD, ma-branche) | Author: Michel Boudran <[email protected]> | Date: Tue Jul 22 23:33:15 2014 0200 | | ajout d'une troisième ligne dans le fichier | * commit dbc6c57019afe80dbb2f3d889eb63cb024656faa | Author: Michel Boudran <[email protected]> | Date: Tue Jul 22 23:33:14 2014 0200 | | ajout d'une seconde ligne dans le fichier | * commit e2cbadc10289e74a131a728e06ac2421e79b5b9f | Author: Michel Boudran <[email protected]> | Date: Tue Jul 22 23:33:14 2014 0200 | | ajout d'un fichier | * commit a59a042e1a7f1474a11c0bd2585ab2eb71b85c47 (origin/master, origin/HEAD, master) |\ Merge: 5c511f2 12c8449 | | Author: Darkdadaah <[email protected]> | | Date: Sat May 25 08:49:21 2013 0000 | | | | Merge "TEST 1" | |
Examinons ce graphique : master est en retard tandis que ma-branche est en avance de trois commits.
Fusionner la branche dans master (merge)
[modifier | modifier le wikicode]Supposons que nous sommes satisfaits du travail réalisé dans notre branche. Nous avons fait plusieurs commits, nous avons vérifié que nous n'avons pas créé de bogue, etc. Supposons que notre branche est prête et qu'on peut intégrer les modifications dans master.
D'abord, se placer sur master :
git checkout master
Switched to branch 'master'
Puis demander à git de fusionner la branche ma-branche, sans fast forward[1] pour éviter de perdre la topologie de la branche :
git merge ma-branche --no-ff -m "intégration de ma nouvelle fonctionnalité dans master"
Git va faire un commit pour intégrer les changements. Comme précédemment, nous avons choisi d'utiliser -m
pour préciser le message de commit mais on aurait pu ne rien mettre et git nous aurait ouvert l'éditeur de texte.
Merge made by the 'recursive' strategy. mon_nouveau_fichier.txt | 3 1 file changed, 3 insertions( ) create mode 100644 mon_nouveau_fichier.txt
Examinons
git log --decorate --graph
* commit abd3ef0a5978b90db042bf076e82d64c3576194b (HEAD, master) |\ Merge: a59a042 635ace6 | | Author: Michel Boudran <[email protected]> | | Date: Tue Jul 22 23:43:51 2014 0200 | | | | intégration de ma nouvelle fonctionnalité dans master | | | * commit 635ace69f901dfb1aaff187e6abc54b0c95fe51e (ma-branche) | | Author: Michel Boudran <[email protected]> | | Date: Tue Jul 22 23:33:15 2014 0200 | | | | ajout d'une troisième ligne dans le fichier | | | * commit dbc6c57019afe80dbb2f3d889eb63cb024656faa | | Author: Michel Boudran <[email protected]> | | Date: Tue Jul 22 23:33:14 2014 0200 | | | | ajout d'une seconde ligne dans le fichier | | | * commit e2cbadc10289e74a131a728e06ac2421e79b5b9f |/ Author: Michel Boudran <[email protected]> | Date: Tue Jul 22 23:33:14 2014 0200 | | ajout d'un fichier | * commit a59a042e1a7f1474a11c0bd2585ab2eb71b85c47 (origin/master, origin/HEAD)
On retrouve bien quatre commits nous appartenant (symbolisés par une * dans le graphe). On retrouve les trois premières modifications et un quatrième commit pour le merge
. On voit que les branches ont convergé sur le graphique et que master est de nouveau sur la première ligne tout en haut du graphe. Nos changements ont bien été intégré à master.
Effacer une branche
[modifier | modifier le wikicode]Locale
[modifier | modifier le wikicode]Nos changements sont intégrés à master, la branche est désormais inutile. Supprimons-la :
git branch -d ma-branche
Deleted branch ma-branche (was 635ace6).
La suppression de la branche peut échouer si la branche à supprimer n'a pas été fusionnée dans master :
git branch -d ma-branche
error: The branch 'ma-branche' is not a strict subset of your current HEAD. If you are sure you want to delete it, run 'git branch -D dev'.
Git se prémunit donc d'effacer des changements potentiellement non vérifiés. Comme git l'indique, on peut forcer la suppression malgré tout :
git branch -D ma-branche
NB : une branche ne peut pas être supprimée si on n'a pas fait le dernier commit.
Distante
[modifier | modifier le wikicode]git push <remote_name> --delete <branch_name>
Supprimer les veilles branches
[modifier | modifier le wikicode]Lorsque l'on tape "git branch" après un certain temps, la branche active apparait au milieu d'une multitude d'anciennes branches généralement fusionnées, et donc inutile de conserver en local. Pour les nettoyer on utilise donc :
git remote prune origin
Mais parfois il reste encore un paquet de branches locales qui ont été mergées sur le serveur. Pour éviter d'avoir à les supprimer une par une :
git branch -D `git branch --merged | grep -v \* | xargs`
Sinon, nommer la branche dans laquelle elles furent fusionnées. Par exemple, pour supprimer les branches mergées dans "master" :
git branch -D `git branch --merged master | grep -v \* | xargs`
Renommer une branche
[modifier | modifier le wikicode]Il faut renommer la locale, supprimer la distante, puis pusher la locale :
git branch -m vieille_branche nouvelle_branche
git push origin :vieille_branche
git push --set-upstream origin nouvelle_branche
L'option --set-upstream
(alias -u
) s'utilise uniquement à la création de la branche sur le serveur distant. Elle doit ensuite être mise à jour avec push
tout court.
Continuer
[modifier | modifier le wikicode]Vous pouvez à tout moment créer des nouvelles branches depuis master et ce, à chaque nouvelle fonctionnalité ou nouvelle modification qu'il faudrait apporter au projet. Git vous permet de gérer plusieurs branches en parallèle et ainsi de cloisonner vos travaux et d'éviter de mélanger des modifications du code source qui n'ont rien à voir entre elles.
En gardant une branche master saine, vous vous laissez la possibilité de créer de nouvelles branches simplement et vous conservez ainsi une version du logiciel prête à être livrée à tout instant (puisqu'on ne merge
dedans que lorsque le développement est bien terminé.
git log
vous permet de retrouver dans l'historique les branches qui ont été créées, et les différents commits réalisés pour une même fonctionnalité sont bien regroupés entre eux.