Branches et fusion
Créer des branches, basculer, fusionner et gérer un conflit.
Objectifs
À la fin de cette leçon, vous saurez :
- expliquer qu'une branche est un simple pointeur vers un commit — et pourquoi c'est révolutionnaire ;
- créer une branche, y travailler, revenir sur main, observer les allers-retours ;
- fusionner avec
merge, en distinguant fast-forward et fusion à commit ; - résoudre un conflit basique sans panique.
🔗 Pour vous rafraîchir la mémoire : vos premiers commits
Une branche n'est pas une copie
Idée reçue quasi universelle chez les débutants : créer une branche dupliquerait le projet. Faux, et c'est une excellente nouvelle. Une branche est un pointeur — techniquement, un fichier de 41 octets contenant le hash d'un commit :
A ← B ← C
↑
main (main « dit » : le dernier commit est C)
Créons une branche et committons dedans :
A ← B ← C ← D ← E
↑ ↑
(main) feature
Que s'est-il passé ?
git branch feature: un second pointeur naît, visant C comme main. Coût réel : 41 octets, zéro copie de fichier ;- pendant qu'on travaille sur
feature, chaque nouveau commit fait avancer le pointeur courant : D puis E ; main, lui, n'a pas bougé : il vise toujours C.
Le mécanisme entier tient là : les branches sont des étiquettes mobiles posées sur une chaîne immuable de commits. C'est ce qui rend leur création instantanée et leur manipulation sans danger — on déplace des étiquettes, jamais des fichiers.
HEAD est l'étiquette supplémentaire « vous êtes ici » : elle pointe la branche active, qui pointe son dernier commit.
Créer et naviguer
git branch feature # crée le pointeur (sans y aller)
git switch feature # déplace HEAD : vous êtes désormais SUR feature
Faites quelques modifications et commits... puis l'expérience décisive :
git switch main # retour sur main
ls # vos modifications de feature ont DISPARU du disque !
git switch feature
ls # ...et les revoilà
Rien n'a été perdu ni retrouvé : le répertoire de travail reflète toujours le commit visé par HEAD. Basculer de branche, c'est demander à Git de reconstruire vos fichiers tels qu'ils étaient au moment du commit ciblé. Vos essais de feature vivent tranquillement dans l'historique de cette branche pendant que main reste propre.
Raccourci courant : git switch -c feature crée ET bascule en un seul geste. Pour visualiser tout le monde :
git log --oneline --all --graph
* e5f6a7b (feature) Ajoute notes.md
* d4c3b2a Travaille sur feature
* c3b2a1d (main) Premier commit
Fusionner
Scénario : sur feature, deux commits ont ajouté un fichier notes.md. Retour sur main :
git switch main
git merge feature
Deux cas possibles :
Cas 1 — fast-forward (main n'a pas bougé pendant votre travail) : l'historique est linéaire, Git se contente de faire glisser l'étiquette main jusqu'à E :
avant : A ← B ← C (C = main) C ← D ← E (E = feature)
après : A ← B ← C ← D ← E
↑ ↑
feature main ← simple glissement d'étiquette
Cas 2 — fusion à commit (main a AVANCÉ entre-temps) : les deux chaînes divergent ; Git fabrique un commit de fusion avec deux parents, qui rassemble les deux lignées :
A ← B ← C ← F ← G (F = commit de fusion, parents C et E)
↑ ↑
main E (feature)
Dans les deux cas, notes.md existe désormais sur main. Vérifiez avec ls et git log --oneline.
Le conflit : normal, fréquent, gérable
Un conflit survient quand deux branches modifient la même ligne différemment. Git refuse alors de choisir à votre place et marque le fichier :
Créons-le volontairement : sur main, modifiez la ligne 1 de README.md (« Version principale »), commitez ; puis sur feature, modifiez la MÊME ligne autrement (« Version expérimentale »), revenez sur main, git merge feature :
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
Ouvrons le fichier :
<<<<<<< HEAD
Version principale
=======
Version expérimentale
>>>>>>> feature
Lecture des marqueurs : <<<<<<< HEAD ouvre votre version (celle de main), ======= sépare, >>>>>>> feature referme l'autre. Entre les deux, aucune magie possible : c'est une décision humaine. Protocole complet :
- ouvrir le fichier ;
- écrire le contenu final voulu (garder l'un, garder l'autre, ou COMBINER les deux — cas le plus fréquent en vrai) ;
- supprimer les trois marqueurs
<<<<<<<,=======,>>>>>>>; git add README.md(dire « conflit résolu ») ;git commitpour conclure la fusion.
Et si vous vous êtes lancé dans un merge par erreur ? Échappatoire prévue : git merge --abort remet tout exactement comme avant.
Retenez la philosophie : un conflit n'est pas une panne. C'est Git qui détecte une vraie ambiguïté — deux auteurs ont voulu deux choses différentes au même endroit — et refuse de trancher silencieusement. Le jour où vous collaborerez, chaque conflit sera une conversation rendue possible par l'outil.
Exercice
- Dans votre dépôt
carnet-de-bord, créez la brancheideesdepuis main. - Ajoutez-y un fichier
idees.txtavec trois idées, commitez. - Revenez sur main : vérifiez que
idees.txta disparu du disque. Expliquez pourquoi il n'est pas perdu. - Sur
idees, modifiez aussi la première ligne dejour-01.md. Puis sur main, modifiez LA MÊME ligne différemment et committez. Fusionnezideesdans main : résolvez le conflit en combinant les deux versions. - Affichez le graphe final avec
git log --oneline --all --graph.
Résumé
- Branche = pointeur mobile vers un commit ; création instantanée, coût nul.
switchdéplace HEAD ; le disque reflète toujours le commit visé.- Fast-forward si l'historique est linéaire ; commit de fusion sinon.
- Conflit = même ligne modifiée deux fois : décision humaine encadrée par les marqueurs ;
merge --abortannule tout.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Exercice 3. Le fichier n'existe plus sur le disque car le répertoire de travail reflète désormais le commit courant de main — lequel ne contient pas idees.txt. Mais le commit qui l'ajoute existe toujours dans l'historique de la branche idees : un git switch idees suivi de ls le fait réapparaître instantanément. Rien n'a été supprimé, seulement « déplacé hors de vue ».
Exercice 4. Résolution attendue du conflit — combinée, pas arbitraire :
Votre ligne depuis main (ex.) : « Jour un : mise en place »
Votre ligne depuis idees : « Jour un : mise en place + idées »
Combinaison retenue : « Jour un : mise en place et premières idées »
Puis :
git add jour-01.md
git commit # conclut la fusion
Notez le message de Git au moment du commit : il propose un message par défaut (« Merge branch 'idees' ») — conservez-le, il documente précisément l'événement.
Exercice 5. Graphe attendu (avec le conflit résolu, donc fusion à commit) :
* Merge branch 'idees'
|\
| * Modifie la première ligne depuis idees
| * Ajoute idees.txt
* | Modifie la première ligne depuis main
|/
* Démarre le carnet de bord
Le losange (|\ puis |/) montre la divergence et le commit de fusion à deux parents qui la referme. Si main n'avait PAS bougé pendant votre travail sur idees, la fusion aurait été un simple fast-forward : ligne droite, pas de commit de fusion — les deux formes sont correctes, chacune raconte fidèlement ce qui s'est passé.