Aller au contenu

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.

# Forcer le fast-forward (echoue si divergence)
git merge --ff-only feature
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)"
# Forcer un merge commit (meme si ff possible)
git merge --no-ff feature
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)"
git merge --squash feature
git commit -m "feat: ajouter la fonctionnalite X"
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