En fait, git rebase sert à re-baser une branche, c'est-à-dire à la « débrancher » de la branche dont elle est initialement partie et la reconnecter ailleurs. Généralement, il s'agit de le faire un peu plus en aval sur cette même branche originale, lorsque le travail a un peu trop évolué en parallèle et qu'il faut se resynchroniser avec l'état courant du projet. Par exemple, ici, on rebase la branche de droite, de A vers D :
O z'
|
O y'
|
O x'
/
E O O z E O /
| | |/
D O O y D O
| | |
C O O x → vers → C O
| / |
B O / B O
|/ |
A O A O
Pour ce faire, git « rejoue » les commits « x », « y », et « z », c'est-à-dire qu'il réapplique leurs différentiels respectifs à partir de D comme s'il s'agissait de nouvelles modifications. Et une fois que c'est fait, il déplace simplement l'étiquette de la branche sur le dernier commit.
En ce sens, « rebase » n'est pas à strictement parler l'équivalent d'un merge. Il s'agit simplement de déplacer la branche pour pouvoir continuer à travailler dessus. Évidemment, si la branche originale a trop divergé, les mêmes problèmes qu'avec une fusion (merge) se posent : des conflits. Et ils se résolvent de la même façon.
Si tu pousses ensuite ta branche de travail vers le serveur et que tu l'avais déjà fait au moins une fois auparavant, le serveur ne sait pas qu'elle a été déplacée. Donc, il ne comprend pas le cheminement suivi et c'est là que le « --force » s'impose. Cela signifie « contente-toi de la déplacer à l'endroit actuel et ne te soucie pas de l'historique ». C'est normal dans ce cas de figure, mais on comprend que cela ne doit pas être utilisé sur une branche collaborative : uniquement sur ses branches personnelles.
Une manière propre de le faire si jamais le serveur ne t'autorise pas du tout à le faire consiste à déclarer une nouvelle branche à cet endroit, à pousser cette nouvelle branche, et à supprimer l'ancienne.
Si tu utilises git merge par contre, tu re-fusionnes ta branche avec la branche principale avant de continuer à travailler. À ce moment-là, les deux branches continuent à co-exister mais vont se retrouver temporairement à un endroit commun (le commit G).
G O ← Merge
|\
F O \
| \
E O O z
| |
D O O y
| |
C O O x
| /
B O /
|/
A O
Ou alors, tu intègres ponctuellement les changements de la branche principale dans la tienne. Les deux branches continuent d'être distinctes et tu ne pollues pas la branche principale :
G O
|
F O O ← Merge
| /|
E O / O z
|/ |
D O O y
| |
C O O x
| /
B O /
|/
A O
Dans les deux derniers cas, l'avantage est que tu préserves l'historique. Le serveur est donc au courant du cheminement et te laisse faire. L'inconvénient est que justement, cela introduit un point de fusion officiel visible dans l'historique ensuite, ce qui n'est pas forcément souhaitable. En outre, cela rend plus difficile un éventuel rebase ultérieur.
Du coup la bonne pratique avec rebase serait de pousser sur la branch local puis de push à la fin de la résolution des conflits?
Pas forcément. Il nous faudrait déjà le message d'erreur complet. Ce que tu nous présentes n'est pas suffisant pour conclure. Normalement, si tu as résolu les conflits en local juste après le rebase, tu ne devrais pas avoir de difficulté à pousser le tout ensuite. Il faudrait voir si tu as fait des erreurs pendant le rebasage ou si c'est le serveur qui te l'empêche.
Partager