La différence entre merge et rebase dans Git

Ni rebase ni merge lors d’un pull ne “suppriment” vos travaux — dans les deux cas, vos commits restent dans le dépôt (dans l’histoire de la branche ou sous forme de SHAs anciens tant que le reflog est actif).

  • pull.rebase false (merge) : git pull crée un commit de fusion, vos commits et ceux des autres ne sont pas recopiés, l’histoire de la branche se fusionne simplement. Visuellement, c’est plus sûr pour la tête : vous voyez clairement les lignes qui se rejoignent.
  • pull.rebase true (rebase) : vos commits locaux sont recopiés au-dessus des commits distants (nouveaux hash). Le contenu des commits est généralement identique, mais les “anciens” commits peuvent rester uniquement dans le git reflog après un rebase réussi — c’est normal, d’où ils peuvent être restaurés (git reset --hard vers un ref du reflog) si quelque chose s’est mal passé.

Si la priorité est de “ne pas perdre de travaux” :

  1. Avant les étapes risquées — faites un commit (ou git stash) et, si vous le souhaitez, créer une branche séparée (git branch backup-tgisn-46) — une copie du pointeur, un backup peu coûteux.
  2. Ne confondez pas avec les pertes causées par des commandes comme git reset --hard, force push inutilement, git clean -fd.
  3. Après un rebase/merge, ne lancez pas de git gc agressif pendant quelques jours — le reflog conserve un point d’entrée de secours.

Pratique pour “ne pas perdre de travail, sans compliquer trop l’histoire” : git config pull.rebase false — en cas de conflit, vous obtenez toujours un merge, sans recopie de vos commits locaux. Si vous préférez déjà le mode rebase (comme dans l’ancien pull --rebase) — vous pouvez laisser pull.rebase true, mais évitez les push --force sur des branches partagées sans accord.

Résultat : la perte de travaux ne vient pas du choix de la stratégie pull ; le risque vient d’autres commandes et de force push ; pour plus de tranquillité — commit + branche de sauvegarde avant les opérations ambiguës.

Voici la même situation que vous avez rencontrée : un seul commit commun C, ensuite sur origin cinq commits r1…r5, sur local — un seul L (mon travail).

1. Avant pull (détachés)

gitGraph
  commit id: "C (commun)"
  branch local
  checkout local
  commit id: "L (mon commit)"
  checkout main
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"

Signification : la pointe de local = L, la pointe de main = r5, ancêtre commun = C. Cela n’est pas perdu dans les deux cas — seul le comment l’histoire est assemblée change.


2. Après git pull sans rebase (pull.rebase falsemerge)

gitGraph
  commit id: "C"
  branch local
  checkout local
  commit id: "L"
  checkout main
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"
  checkout local
  merge main
  commit id: "M (commit de fusion)"

Un commit de fusion M apparaît avec deux parents (L et r5). Les commits L et r1…r5 restent en tant qu’objets ; l’histoire est arborescente, sans recopie.


3. Après git pull avec rebase (pull.rebase truerebase)

gitGraph
  commit id: "C"
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"
  commit id: "L′ (même patch, nouveau hash)"

L’histoire est linéaire : votre travail repose au-dessus des commits distants. Le commit L a un nouveau commit L′ (même diff par rapport à r5, hash différent) ; l’ancien L reste visible dans le git reflog pendant un certain temps, tant que vous n’avez pas supprimé reflog expire.


En résumé : merge — dédoublement + nœud de fusion ; rebase — une ligne unique, votre commit “rejoué” au-dessus. Vos travaux, au sens des changements dans les fichiers, ne disparaissent pas dans les deux scénarios normaux ; seule la forme de l’histoire et les hash du commit local changent lors d’un rebase.