Stratégies de merge¶
Fast-forward, merge commit, squash et rebase — comprendre leur impact sur l'historique.
Pourquoi ca compte¶
La stratégie de merge détermine la forme de votre historique Git. Un historique lisible facilite le debug (git bisect), la review et la comprehension du projet. Un historique chaotique rend ces opérations penibles voire impossibles.
Fast-forward¶
Quand la branche cible n'a pas diverge, Git avance simplement le pointeur — aucun commit de merge n'est créé.
gitGraph
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
checkout main
merge feature id: "D (ff)" Avant : main pointe sur B, feature pointe sur D. Après : main pointe sur D. Pas de commit de merge.
| Avantage | Inconvénient |
|---|---|
| Historique lineaire et propre | Pas de trace de la branche dans le graphe |
| Pas de commit de merge | Impossible si main a avance |
Merge commit¶
Crée un commit de merge avec deux parents, même si le fast-forward etait possible.
gitGraph
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
checkout main
commit id: "E"
merge feature id: "M (merge)" | Avantage | Inconvénient |
|---|---|
| La branche est visible dans le graphe | Historique plus touffu |
| Revert simple (revert le commit de merge) | Commits "Merge branch..." repetitifs |
Squash merge¶
Condense tous les commits de la branche en un seul commit sur la branche cible.
gitGraph
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
commit id: "E"
checkout main
commit id: "squash(C+D+E)" | Avantage | Inconvénient |
|---|---|
| Un commit propre par feature | Perte du détail des commits intermédiaires |
| Historique de main très lisible | La branche n'est pas marquée comme mergee |
| Idéal pour les petites features | Difficile sur les grosses branches (perte de contexte) |
Branche non marquée comme mergee
Après un squash merge, Git ne sait pas que la branche a été intégrée. Pensez à la supprimer manuellement pour éviter la confusion.
Rebase¶
Rejoue les commits de la branche sur la pointe de la branche cible, creant de nouveaux commits avec de nouveaux hashes.
gitGraph
commit id: "A"
commit id: "B"
commit id: "E"
commit id: "C'"
commit id: "D'" # Sur la feature branch
git rebase main
# Puis fast-forward merge
git checkout main
git merge --ff-only feature
| Avantage | Inconvénient |
|---|---|
| Historique parfaitement lineaire | Reecrit l'historique — dangereux si déjà pousse |
| Chaque commit de la feature est conserve | Conflits a résoudre commit par commit |
| Idéal avec bisect | Plus complexe que merge |
Ne jamais rebase une branche partagee
git rebase reecrit les hashes des commits. Si d'autres développeurs ont base du travail sur ces commits, leurs branches deviendront incoherentes. Règle d'or : ne rebasez que les branches que vous etes le seul a utiliser.
Comparatif¶
| Critère | Fast-forward | Merge commit | Squash | Rebase |
|---|---|---|---|---|
| Historique lineaire | Oui | Non | Oui | Oui |
| Trace de la branche | Non | Oui | Non | Non |
| Détail des commits | Oui | Oui | Non | Oui |
| Risque rewrite | Non | Non | Non | Oui |
| Complexité conflits | Nulle | Faible | Faible | Par commit |
| Adapté pour bisect | Oui | Moyen | Non | Oui |
Recommandation
Il n'y a pas de stratégie universelle. Mais voici un point de départ pragmatique :
- Petites features (1-3 commits) → squash merge pour un historique propre
- Features significatives → rebase + fast-forward pour garder le détail
- Branches de release → merge commit pour tracer l'intégration
Outils¶
| Outil | Description | Lien |
|---|---|---|
| git merge | Commande native — supporte ff, no-ff, squash | Inclus avec Git |
| git rebase | Rejoue des commits sur une autre base | Inclus avec Git |
| Options de forge | Chaque forge (GitHub, GitLab, Gitea) propose un choix de stratégie au moment du merge de la MR/PR | Config projet |